一键导入
async-traits
JOB-252 — async_trait overhead, native async fn in traits (Rust 1.75+), and when each applies.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
JOB-252 — async_trait overhead, native async fn in traits (Rust 1.75+), and when each applies.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
AgentExecutor, ChatAgent (ReAct), OpenAIToolsAgent, and the Agent trait.
JOB-251 — Why Arc<dyn LLM> over LLMClone, migration pattern, and correct LLM ownership model.
All Chain types — LLMChain, ConversationalChain, SequentialChain, StuffDocuments, ConversationalRetrievalQA, SqlDatabaseChain.
Trait conformance tests, property-based tests (proptest), fuzz targets, and boundary contracts for langchainx traits.
Core langchainx patterns — LLMChain, builder pattern, Chain trait, prompt macros, and basic invocation.
Constructing LLM backends (OpenAI, Claude, DeepSeek, Qwen, Ollama) and configuring CallOptions.
| name | async-traits |
| description | JOB-252 — async_trait overhead, native async fn in traits (Rust 1.75+), and when each applies. |
Every trait in this codebase uses #[async_trait]:
#[async_trait]
pub trait LLM: Sync + Send {
async fn generate(&self, messages: &[Message]) -> Result<GenerateResult, LLMError>;
// desugars to:
// fn generate(...) -> Pin<Box<dyn Future<Output=Result<...>> + Send + 'async_trait>>
}
This means every generate() call heap-allocates a Box<dyn Future>. With 124 uses
across 60 files, this is pervasive.
For static dispatch (generics), native async fn works without any macro:
// No #[async_trait] needed — works for static dispatch
pub trait LLM: Sync + Send {
async fn generate(&self, messages: &[Message]) -> Result<GenerateResult, LLMError>;
async fn stream(&self, messages: &[Message])
-> Result<Pin<Box<dyn Stream<Item = Result<StreamData, LLMError>> + Send>>, LLMError>;
}
// Generic function — zero-cost, no boxing
async fn run_chain<L: LLM>(llm: &L, messages: &[Message]) -> Result<String, LLMError> {
Ok(llm.generate(messages).await?.generation)
}
## dyn Trait Limitation
async fn in dyn Trait still requires boxing as of Rust 1.85. At dyn call sites, use
a local adapter:
use async_trait::async_trait;
// Thin wrapper that adds boxing only at the dyn boundary
#[async_trait]
trait DynLLM: Send + Sync {
async fn generate(&self, messages: &[Message]) -> Result<GenerateResult, LLMError>;
}
// Blanket impl bridges native LLM → DynLLM
impl<L: LLM + Send + Sync> DynLLM for L {
async fn generate(&self, messages: &[Message]) -> Result<GenerateResult, LLMError> {
LLM::generate(self, messages).await
}
}
Or keep Arc<dyn LLM> with #[async_trait] on just the trait definition — boxing happens
once at the trait boundary, not in every impl.
#[async_trait] to new trait impls — consistent with existing codeasync_trait uses to non-trait code (closures, free functions)LLM trait (highest call frequency), measure, then
proceed to Tool, Chain, Embedder