from_config() 编译器需求规格文档YAML Agent Configuration → Lambda Term Compiler
版本: 2.0 | 状态: 需求定稿 | 上游理论: LDS ≡ Lambda Calculus
from_config(path) 是一个编译器,输入 YAML 格式的 Agent 配置文件,输出一个可执行的 lambdagent.Term(Lambda 项)。
from_config("agent-config.yml") → Term → term(input) → result
↓ ↓ ↓
YAML 解析 Lambda 项 β-规约
等价于手写:
Memory(
Loop(
think >> Route(tools) >> observe,
max_steps=20
),
store=redis(20, 7200)
)
| 原则 | 说明 |
|---|---|
| 每个 YAML 字段有且仅有一个 Lambda 语义 | 不存在"无法翻译"的配置项 |
| 编译结果可追踪 | 每一步执行 = 一次 β-规约,记录在 Context.trace |
| 编译结果可静态分析 | lint 工具能从 Term 结构推断配置问题 |
| 编译是确定性的 | 同一 YAML 总产出同一 Term 结构 |
| 编译器不执行 Agent | from_config 只构建 Term,不调用 LLM |
# ═══ 必填字段 ═══
agentId: string # Agent 唯一标识符
name: string # Agent 可读名称
type: enum # "react" | "chain" | "simple" | "parallel" | "router"
systemPrompt: string # Lambda body(λ 抽象的函数体)
# ═══ 模型配置 ═══
model:
provider: string # "anthropic" | "openai" | "dashscope" | "custom"
name: string # 具体模型名 (e.g., "claude-sonnet-4-20250514")
temperature: float # [0.0, 2.0],默认 0.0
maxTokens: int # 最大输出 token 数,默认 1024
topP: float # [0.0, 1.0],可选
stopSequences: [string] # 停止序列,可选
baseUrl: string # 自定义 API 端点,可选
# ═══ ReAct 配置(type=react 时必填)═══
react:
maxSteps: int # Y 组合子最大展开次数,默认 10
observationEnabled: bool # 是否将工具结果追加到上下文,默认 true
toolTimeout: int # 单个工具调用超时(秒),默认 30
verbose: bool # 是否打印中间步骤,默认 false
earlyStop: string # 提前终止条件表达式,可选
thinkPrompt: string # 覆盖 think 步骤的 prompt,可选
# ═══ Chain 配置(type=chain 时必填)═══
chain:
steps: # 有序步骤列表
- name: string # 步骤名称
prompt: string # 该步骤的 prompt
model: object # 可选覆盖模型配置
outputParser: string # "json" | "text" | "number" | "boolean"
guard: # 可选输出验证
validator: string # Python 表达式 (e.g., "len(x) > 100")
retry: int # 验证失败重试次数
fallback: string # 兜底值
# ═══ Router 配置(type=router 时必填)═══
router:
classifier: # 分类器配置
prompt: string # 分类 prompt
model: object # 可选模型覆盖
categories: [string] # 类别列表
routes: # 类别 → Agent 映射
<category>: # 每个 category 指向一个子 agent 配置
type: string
systemPrompt: string
# ... 子 agent 的完整配置
default: object # 无法分类时的默认 Agent,可选
# ═══ Parallel 配置(type=parallel 时必填)═══
parallel:
agents: # 并行 Agent 列表
- name: string
type: string
systemPrompt: string
# ... 子 agent 完整配置
merge: string # 结果合并策略: "tuple" | "concat" | "custom"
mergePrompt: string # merge=custom 时的合并 prompt
# ═══ MCP 工具配置 ═══
mcp:
onlineTool: # 在线 MCP 工具
<server-name>: # MCP 服务器名
- string # 工具名列表
localTools: [string] # 本地工具("terminate" 是特殊的 base case)
policy:
mode: string # "auto" | "force" | "intelligence" | "disable"
maxConcurrent: int # 最大并行工具调用数,默认 1
retryOnFail: int # 工具调用失败重试次数,默认 0
# ═══ Memory 配置 ═══
memory:
enabled: bool # 是否启用
strategy: string # "local" | "redis" | "sqlite" | "custom"
size: int # 记忆容量(最多保留多少条)
ttl: int # 过期时间(秒),0 = 永不过期
scope: string # "session" | "global" | "user"
customStore: string # strategy=custom 时的 Python 类路径
# ═══ Guard 配置(可选,包裹整个 Agent)═══
guard:
validator: string # Python 表达式
retry: int # 重试次数
fallback: string # 兜底策略: "error" | "empty" | "last"
# ═══ RAG 配置(可选)═══
rag:
enabled: bool
source: string # 知识库路径或 URL
topK: int # 检索数量,默认 3
chunkSize: int # 分块大小
backend: string # "simple" | "chroma",默认 "simple"
minScore: float # 最低相似度阈值,默认 0.0
format: string # "numbered" | "plain" | "json",默认 "numbered"
agentic: bool # true = AgenticRAG(Agent 自行决定是否检索)
persistDirectory: string # backend=chroma 时的持久化目录
# ═══ 外部服务配置 ═══
app:
mcp:
custom:
nodes:
<server-name>:
url: string # MCP 服务端点
endpoint: string # 路径
headers:
Authorization: string
timeout: int # 超时(秒)
| 级别 | 字段 | Lambda 语义 | 编译行为 |
|---|---|---|---|
| 必须 | type, systemPrompt |
Agent 结构 + λ body | 缺失则报编译错误 |
| 核心 | model, react, mcp |
计算单元 + Y 参数 + Oracle | 缺失则用默认值 |
| 增强 | memory, guard, chain, router, parallel |
环境扩展 + 类型约束 + 组合 | 缺失则不包裹 |
| 元数据 | agentId, name, description |
不影响 Lambda 语义 | 只用于标识和追踪 |
| 运行时 | rag, app |
外部资源 | 传递给 Tool 实现层 |
def from_config(path: str, **overrides) -> Term:
"""
编译 YAML 配置为 Lambda 项。
参数:
path: YAML 文件路径
**overrides: 运行时覆盖项
- model: 覆盖模型名称
- temperature: 覆盖温度
- max_steps: 覆盖最大步数
- tools: Dict[str, Callable] 注入自定义工具实现
- memory_store: Dict 注入初始记忆
返回:
Term — 可执行的 Lambda 项
异常:
ConfigError — YAML 解析失败
SchemaError — 必填字段缺失
CompileError — 语义不合法 (e.g., router 无 routes)
"""
type: simple — 单个 λ 抽象输入 YAML:
type: simple
systemPrompt: "Summarize text."
model: {name: claude-sonnet}
编译目标:
Lam("agent", prompt="Summarize text.", model="claude-sonnet")
Lambda:
λx. LLM_{θ,p}(x)
type: react — Y 组合子输入 YAML:
type: react
react: {maxSteps: 20}
mcp:
onlineTool: {server: [search, calc]}
localTools: [terminate]
编译目标:
Memory(
Loop(
Tool("react_step", fn=react_step_fn),
condition=lambda r, s: s >= 19,
max_steps=20
),
store={...}
)
其中 react_step_fn 内部结构:
think(state) ← Lam: β-规约
→ Route(thought, { ← 广义 Church 布尔
"search": Tool("search", mcp),
"calc": Tool("calc", mcp),
"terminate": Tool("terminate", λx.x) ← base case
})
→ observation ← 工具结果
→ state ⊕ observation ← 状态拼接
Lambda:
Memory(
Y₂₀(λself.λstate.
let t = think(state) in
CASE t [
(search, Tool_MCP(t)),
(calc, Tool_MCP(t)),
(terminate, λx.x) ← base case
] >>
IF is_terminate THEN t
ELSE self(state ⊕ obs)
),
Γ ∪ store
)
type: chain — 函数组合链输入 YAML:
type: chain
chain:
steps:
- name: extract
prompt: "Extract key facts."
- name: analyze
prompt: "Analyze the facts."
guard: {validator: "len(x) > 50", retry: 2}
- name: draft
prompt: "Write a draft."
编译目标:
Lam("extract", "Extract key facts.")
>> Guard(
Lam("analyze", "Analyze the facts."),
validator=lambda x: len(x) > 50,
retry=2
)
>> Lam("draft", "Write a draft.")
Lambda:
λx. draft(Guard(analyze, P)(extract(x)))
where P(r) = len(r) > 50
type: router — 广义 Church 布尔 (CASE)输入 YAML:
type: router
router:
classifier:
prompt: "Classify: code/math/general"
categories: [code, math, general]
routes:
code: {type: simple, systemPrompt: "You are a coder."}
math: {type: simple, systemPrompt: "You are a mathematician."}
default: {type: simple, systemPrompt: "You are a helpful assistant."}
编译目标:
Route(
classifier=Lam("classifier", "Classify: code/math/general"),
routes={
"code": Lam("code_agent", "You are a coder."),
"math": Lam("math_agent", "You are a mathematician."),
},
default=Lam("default", "You are a helpful assistant.")
)
Lambda:
λx. CASE (classifier x) [
(code, code_agent x),
(math, math_agent x),
(_, default_agent x)
]
type: parallel — Church 对 (PAIR / PAR)输入 YAML:
type: parallel
parallel:
agents:
- {name: researcher, systemPrompt: "Research the topic."}
- {name: critic, systemPrompt: "Critique the topic."}
merge: custom
mergePrompt: "Synthesize the research and critique."
编译目标:
Par(
Lam("researcher", "Research the topic."),
Lam("critic", "Critique the topic.")
) >> Lam("merge", "Synthesize the research and critique.")
Lambda:
λx. merge(PAIR (researcher x) (critic x))
| YAML 字段 | 编译目标 | Lambda 语义 | 编译函数 |
|---|---|---|---|
systemPrompt + model |
Lam(name, prompt, model, temp) |
λx. LLM_{θ,p}(x) |
_compile_lam() |
type: react |
Loop(body, cond, maxSteps) |
Y_n(λself.λs. ...) |
_compile_react() |
type: chain |
Compose(s1, s2, ..., sn) |
λx. sn(...s2(s1(x))) |
_compile_chain() |
type: router |
Route(classifier, routes) |
CASE |
_compile_router() |
type: parallel |
Par(a1, a2, ...) >> merge |
PAIR >> merge |
_compile_parallel() |
mcp.onlineTool |
Tool(name, mcp_caller) |
Tool_MCP (Oracle) |
_compile_tools() |
mcp.localTools: [terminate] |
Tool("terminate", λx.x) |
λx.x (identity = base case) |
_compile_tools() |
memory: {enabled: true} |
Memory(agent, store) |
Γ' = Γ ∪ store |
_compile_memory() |
guard |
Guard(agent, validator, retry) |
{x:T \| P(x)} |
_compile_guard() |
rag: {enabled: true} |
Tool("rag_retrieve", fn) 注入 |
外部 Oracle | _compile_rag() |
子 Agent 配置(router 的 routes、parallel 的 agents)递归调用 build_agent():
def _compile_router(cfg):
classifier = _compile_lam(cfg["router"]["classifier"])
routes = {}
for category, sub_cfg in cfg["router"]["routes"].items():
routes[category] = build_agent(sub_cfg) # 递归编译
default = build_agent(cfg["router"]["default"]) if "default" in cfg["router"] else None
return Route(classifier, routes, default)
1. 核心: Lam / Compose / Loop / Route / Par ← 最内层
2. Guard: 包裹核心 Agent ← 输出验证
3. Memory: 最外层包裹 ← 环境扩展
编译伪代码:
agent = compile_core(cfg) # Step 1
if cfg.guard:
agent = Guard(agent, ...) # Step 2
if cfg.memory.enabled:
agent = Memory(agent, store) # Step 3
return agent
ReAct 是最复杂的编译目标,单独详述。
react_agent = Memory(
Y_n(λself. λstate.
let thought = think(state) in ← β-规约
let tool = route(thought, tools) in ← CASE
let obs = tool(thought) in ← β-规约
IF (tool = terminate)
THEN thought ← base case
ELSE self(state ⊕ format(thought, obs)) ← 递归
),
Γ ∪ store
)
def _compile_react(cfg) -> Term:
think = _compile_lam(cfg)
tools = _compile_tools(cfg)
max_steps = cfg["react"]["maxSteps"]
tool_timeout = cfg["react"].get("toolTimeout", 30)
observation_enabled = cfg["react"].get("observationEnabled", True)
def react_step(state: str) -> str:
# Phase 1: Think (β-规约)
thought = think(state)
# Phase 2: Tool Selection (Route / CASE)
selected_tool = _extract_tool_call(thought, tools)
# Phase 3: Base Case Check
if selected_tool is None or selected_tool._name == "terminate":
return thought # λx.x — 递归终止
# Phase 4: Tool Execution (β-规约)
try:
observation = _timeout_call(selected_tool, thought, tool_timeout)
except TimeoutError:
observation = f"[TIMEOUT after {tool_timeout}s]"
# Phase 5: State Update (递归准备)
if observation_enabled:
return _format_state(state, thought, selected_tool._name, observation)
else:
return thought
body = Tool(f"{cfg['name']}.react_step", react_step)
return Loop(
body=body,
condition=lambda r, s: s >= max_steps - 1,
max_steps=max_steps,
)
_extract_tool_call)def _extract_tool_call(thought: str, tools: Dict[str, Tool]) -> Tool | None:
"""
从 LLM 输出中提取工具调用意图。
支持三种格式:
1. 结构化 JSON: {"tool": "search", "args": "query"}
2. XML 标签: <tool>search</tool><args>query</args>
3. 关键词匹配: thought 中包含工具名
优先级: JSON > XML > 关键词
返回: 匹配的 Tool 实例,或 None(表示不调用工具 → 隐式 terminate)
"""
_format_state)def _format_state(state, thought, tool_name, observation) -> str:
"""
构建下一轮 ReAct 的输入状态。
格式:
[Previous Context]
{state}
[Step N]
Thought: {thought}
Action: {tool_name}
Observation: {observation}
这个拼接操作对应 Lambda 演算中的 state ⊕ obs。
"""
def _compile_mcp_caller(server_name: str, tool_name: str, app_cfg: dict) -> Callable:
"""
构造一个 MCP 工具调用函数。
输入: server 配置 (url, endpoint, headers)
输出: Callable[[str], str]
HTTP 调用流程:
POST {url}{endpoint}
Headers: Authorization: {token}, Content-Type: application/json
Body: {"tool": tool_name, "input": input_text}
Response: {"output": "..."}
错误处理:
- 网络超时 → 返回 "[MCP_TIMEOUT: {server}/{tool}]"
- HTTP 4xx/5xx → 返回 "[MCP_ERROR: {status}]"
- JSON 解析失败 → 返回原始 response text
重试策略(由 mcp.policy.retryOnFail 控制):
- 指数退避: delay = min(2^attempt * 1s, 30s)
- 最大重试次数: retryOnFail(默认 0,即不重试)
"""
# terminate 永远编译为恒等函数,不管 YAML 怎么写
if tool_name == "terminate":
return Tool("terminate", fn=lambda x: x)
# Lambda 语义: λx.x
# 这是 Y 组合子的 base case
# react_step 检测到 terminate 被选中时,停止递归
class MemoryStore(ABC):
"""Memory 的存储后端接口"""
@abstractmethod
def get(self, key: str) -> Any | None: ...
@abstractmethod
def put(self, key: str, value: Any, ttl: int = 0) -> None: ...
@abstractmethod
def list_recent(self, n: int) -> List[Tuple[str, Any]]: ...
@abstractmethod
def clear(self) -> None: ...
| strategy | 实现 | 持久性 | 并发安全 |
|---|---|---|---|
local |
Python dict + LRU | 进程内 | 否 |
redis |
Redis hash | 跨进程 | 是 |
sqlite |
SQLite 表 | 磁盘 | 是(单写) |
custom |
用户提供类路径 | 取决于实现 | 取决于实现 |
def _compile_memory(agent: Term, memory_cfg: dict) -> Term:
"""
Memory 编译 = 环境扩展 Γ' = Γ ∪ store
注入方式: 将记忆内容序列化后追加到每次 Agent 调用的输入前面
格式:
[Memory Context]
- key1: value1 (2min ago)
- key2: value2 (15min ago)
... (最近 {size} 条)
[Current Input]
{original_input}
记忆自动管理:
- 每次 Agent 输出后,自动摘要存入 memory
- 超过 size 的旧记忆 LRU 淘汰
- 超过 ttl 的记忆自动删除
"""
| ID | 级别 | 条件 | Lambda 含义 | 消息 |
|---|---|---|---|---|
| L001 | ERROR | systemPrompt 为空 |
λx.⊥ — 函数体未定义 |
"Agent 无行为定义" |
| L002 | ERROR | model 未配置 |
无 LLM 计算单元 | "无法执行 β-规约" |
| L003 | ERROR | react.maxSteps = 0 |
Y₀(g) = ⊥ |
"Agent 不会执行" |
| L004 | ERROR | type: react 且无 terminate |
Y 无 base case | "可能无限循环" |
| L005 | ERROR | type: router 且 routes 为空 |
CASE 无分支 | "路由无目标" |
| L006 | ERROR | type: chain 且 steps 为空 |
空组合链 | "Pipeline 无步骤" |
| L007 | WARN | temperature > 1.5 |
高熵 ⊕_p |
"输出可能不稳定" |
| L008 | WARN | memory.ttl = 0 且 enabled |
Γ' 绑定永不回收 | "内存可能无限增长" |
| L009 | WARN | memory.size = 0 且 enabled |
Γ' = Γ ∪ ∅ = Γ |
"Memory 无效果" |
| L010 | WARN | react.maxSteps > 50 |
Y₅₀+ |
"长运行高成本" |
| L011 | WARN | ReAct 除 terminate 外无工具 | 纯推理循环 | "Agent 只能思考" |
| L012 | WARN | guard.retry > 5 |
过多重试 | "可能死循环" |
| L013 | WARN | router 无 default |
CASE 不完全 | "未分类输入将报错" |
| L014 | INFO | temperature = 0 |
确定性 Lambda | "确定性模式" |
| L015 | INFO | Memory 已启用 | Γ' = Γ ∪ store |
"有状态 Agent" |
| L016 | INFO | RAG 已启用 | 外部知识 Oracle | "可访问知识库" |
lambdagent lint: agent-config.yml
============================================================
✗ [ERROR] mcp.localTools: 没有 terminate 工具
Lambda: Y 组合子无 base case (λx.x) → 无穷递归
⚠ [WARN] react.maxSteps: maxSteps=50 较大
Lambda: Y₅₀(g) → 最多 50 步 β-规约
ℹ [INFO] memory: 启用记忆 strategy=redis, size=20, ttl=7200s
Lambda: 环境扩展 Γ' = Γ ∪ store(redis)
ℹ [INFO] summary: Agent 'SeeCoderManus' 的 Lambda 结构:
Memory(Loop(think >> act >> observe, max_steps=20), redis)
────────────────────────────────────────────────────────
1 error(s), 1 warning(s), 2 info(s)
from_config.py
├── from_config(path, **overrides) → Term # 入口
├── build_agent(cfg) → Term # 递归编译核心
│ ├── _compile_lam(cfg) → Lam # λ 抽象
│ ├── _compile_react(cfg) → Loop # Y 组合子
│ ├── _compile_chain(cfg) → Compose # 函数组合
│ ├── _compile_router(cfg) → Route # CASE
│ ├── _compile_parallel(cfg) → Par # PAIR
│ ├── _compile_tools(cfg) → Dict[str, Tool] # Oracle 集
│ ├── _compile_memory(agent, cfg) → Memory # 环境扩展
│ └── _compile_guard(agent, cfg) → Guard # 类型约束
├── _resolve_model(model_cfg) → str # 模型名解析
├── _compile_mcp_caller(server, tool, app) → Callable # MCP HTTP
├── _extract_tool_call(thought, tools) → Tool | None # 工具匹配
├── _format_state(state, thought, tool, obs) → str # 状态拼接
├── describe_config(path) → str # Lambda 结构可视化
└── to_lambda_expr(path) → str # 导出纯 Lambda 表达式字符串
YAML 文件
│
┌────▼────┐
│ 解析 YAML │
└────┬────┘
│
┌────▼────┐
│ 校验 Schema│ ── 缺必填字段 ──→ SchemaError
└────┬────┘
│
┌────▼────┐
│ 识别 type │
└────┬────┘
│
┌────────┬───┼────────┬──────────┐
▼ ▼ ▼ ▼ ▼
simple react chain router parallel
│ │ │ │ │
_lam() _react() _chain() _router() _parallel()
│ │ │ │ │
└────────┴───┼────────┴──────────┘
│
┌────▼────┐
│ guard? │── yes ──→ Guard(agent, P)
└────┬────┘
│
┌────▼────┐
│ memory? │── yes ──→ Memory(agent, store)
└────┬────┘
│
┌────▼────┐
│ 输出 Term │
└─────────┘
class CompileError(LambdagentError):
"""编译阶段错误(YAML → Term)"""
pass
class SchemaError(CompileError):
"""YAML schema 不合法"""
field: str # 出错的字段路径
expected: str # 期望的类型/值
actual: Any # 实际值
class SemanticError(CompileError):
"""语义不合法(schema 合法但逻辑矛盾)"""
rule: str # 违反的 lint 规则 ID
| 阶段 | 示例 | 异常类型 | 应对 |
|---|---|---|---|
| 解析 | YAML 语法错误 | yaml.YAMLError |
报位置 |
| Schema | type 字段缺失 |
SchemaError |
报字段路径 |
| 语义 | router 无 routes | SemanticError |
报 lint 规则 |
| 运行时 | LLM API 超时 | LambdagentError |
记入 trace |
| 运行时 | Guard 验证失败 | ValidationError |
重试或 fallback |
| 运行时 | Route 无匹配 | RouteError |
走 default 或报错 |
from_config("agent.yml", providers={
"dashscope": DashScopeProvider(api_key="sk-..."),
"openai": OpenAIProvider(api_key="sk-..."),
})
from_config("agent.yml", tools={
"web_search": lambda q: requests.get(f"https://api.search.com?q={q}").json(),
"run_code": lambda code: exec_sandbox(code),
})
from_config("agent.yml", memory_store=MyRedisStore(host="localhost"))
agent = from_config("agent.yml")
agent = agent >> Tool("postprocess", my_cleanup_fn) # 在编译结果后追加步骤
| 测试 | 输入 | 期望输出 Term 类型 | 验证方式 |
|---|---|---|---|
| T01 | type: simple |
Lam |
isinstance(term, Lam) |
| T02 | type: react, maxSteps: 20 |
Loop(max_steps=20) 或 Memory(Loop(...)) |
检查 Loop.max_steps |
| T03 | type: chain, steps: [a, b, c] |
Compose(3 stages) |
len(term.stages) == 3 |
| T04 | type: router, routes: {x, y} |
Route(2 routes) |
len(term.routes) == 2 |
| T05 | type: parallel, agents: [a, b] |
Par(2 agents) >> merge |
检查 Par + Compose |
| T06 | memory.enabled: true |
最外层是 Memory |
isinstance(term, Memory) |
| T07 | guard.validator 存在 |
内含 Guard |
递归查找 Guard |
| T08 | terminate in localTools |
包含 Tool("terminate", λx.x) |
检查 fn 是恒等函数 |
| 测试 | 输入 YAML | 执行输入 | 验证 |
|---|---|---|---|
| E01 | 现有 agent-cofig.yml |
"1+1等于几" | 返回包含 "2" 的字符串 |
| E02 | simple agent | "Hello" | 返回非空字符串 |
| E03 | chain agent (3 steps) | 一段文本 | Context.trace 有 3 条 |
| E04 | router agent | 代码问题 | 路由到 code agent |
| E05 | react agent (有 terminate) | 简单问题 | 在 maxSteps 内终止 |
| 测试 | 输入配置 | 期望 lint 结果 |
|---|---|---|
| L_T01 | 无 systemPrompt | ERROR L001 |
| L_T02 | react 无 terminate | ERROR L004 |
| L_T03 | maxSteps=0 | ERROR L003 |
| L_T04 | router 无 routes | ERROR L005 |
| L_T05 | 正常配置 | 0 errors |
| L_T06 | temperature=2.0 | WARN L007 |
| 能力 | v1 (当前) | v2 (本规格) | 工作量 |
|---|---|---|---|
type: simple |
✅ | ✅ | 无 |
type: react |
✅ (基础) | ✅ (完整工具提取) | 中 |
type: chain |
❌ | ✅ | 新增 |
type: router |
❌ | ✅ | 新增 |
type: parallel |
❌ | ✅ | 新增 |
| MCP HTTP 调用 | ❌ (占位) | ✅ (真实 HTTP) | 中 |
| 工具调用提取 | 关键词匹配 | JSON + XML + 关键词 | 中 |
| Memory store backend | dict only | local/redis/sqlite/custom | 大 |
| Guard 编译 | ❌ | ✅ | 小 |
| 嵌套子 Agent | ❌ | ✅ (递归 build_agent) | 中 |
| overrides 参数 | ❌ | ✅ | 小 |
| Schema 校验 | ❌ | ✅ | 中 |
| describe_config | ✅ | ✅ (增强) | 小 |
| to_lambda_expr | ❌ | ✅ (导出纯 Lambda) | 中 |
P0 (必须): chain + router + parallel 编译
P1 (重要): MCP 真实 HTTP + 工具调用提取增强
P2 (增强): Schema 校验 + 嵌套子 Agent + overrides
P3 (生态): Memory 多后端 + to_lambda_expr + 自定义 Provider
给后续开发者的速查表,编码时随时参考:
YAML Python (lambdagent) Lambda 演算
───────────────────────── ───────────────────────── ──────────────────
systemPrompt + model Lam("name", prompt, model) λx. LLM_{θ,p}(x)
agent(input) term("hello") (f x) → β-规约
type: chain f >> g >> h λx. h(g(f(x)))
type: react + maxSteps Loop(body, cond, N) Y_N(λself.λx...)
type: router Route(cls, {k: agent}) CASE
type: parallel Par(a, b) >> merge PAIR >> merge
mcp.onlineTool Tool("name", http_fn) Oracle / primitive
terminate Tool("terminate", λx.x) λx.x (identity)
memory Memory(agent, store) Γ' = Γ ∪ store
guard Guard(agent, P, retry) {x:T | P(x)}
temperature Lam(..., temperature=T) ⊕_T (概率参数)
maxSteps Loop(..., max_steps=N) Y_N (有界 Y)
CLI 是 lambdagent 的第一公民交互界面,不是附属品。理由:
f(x),CLI 就是 lambdagent run config.yml "input"lambdagent <command> [options] [arguments]
Commands:
compile 编译 YAML → Lambda 项(不执行)
run 编译 + 执行
repl 交互式 REPL(持续对话)
lint 静态分析
trace 查看/回放 β-规约追踪
lambda 导出纯 Lambda 表达式
serve 启动 HTTP/MCP 服务
tools 管理工具(MCP 发现/测试)
version 版本信息
lambdagent compile — 编译(不执行)# 编译并打印 Lambda 结构
lambdagent compile agent-config.yml
# 输出:
# SeeCoderManus =
# Memory(
# Y₂₀(λself.λstate.
# let t = think(state) in
# CASE t [(sum, Tool_MCP), (improve, Tool_MCP), (terminate, λx.x)]
# >> IF is_terminate THEN t ELSE self(state ⊕ obs)
# ),
# redis(size=20, ttl=7200)
# )
#
# Constructs used: Lam, Loop, Route, Tool(×3), Memory
# β-reduction bound: max 20 steps
# Base case: terminate = λx.x
# 选项:
# --format text|json|python 输出格式
# --validate 同时运行 lint
# --dry-run 验证所有工具可达(ping MCP 端点)
Lambda 语义:compile = 解析 + 翻译,不触发 β-规约。等价于"写出 Lambda 表达式但不求值"。
lambdagent run — 编译 + 执行# 单次执行
lambdagent run agent-config.yml "帮我写一个快速排序"
# 从 stdin 读取输入
echo "帮我写一个快速排序" | lambdagent run agent-config.yml -
# 从文件读取输入
lambdagent run agent-config.yml --input task.txt
# 选项:
# --trace 打印每步 β-规约
# --trace-file trace.json β-规约追踪保存到文件
# --max-steps N 覆盖 YAML 的 maxSteps
# --temperature T 覆盖 YAML 的 temperature
# --timeout S 总超时(秒)
# --model MODEL 覆盖模型
# --tool NAME=CMD 注入 CLI 工具(见 15.4)
# --env KEY=VALUE 注入环境变量到 Memory
# --output FILE 结果输出到文件
# --format text|json 输出格式
# --quiet 只输出最终结果,不打印过程
# --verbose 打印所有中间步骤
Lambda 语义:run = compile + β-规约。run config.yml "input" 等价于 (from_config("config.yml")) ("input")。
--trace 输出格式:
β[0] think (2.8s) "帮我写快速排序" → "需要调用代码工具..."
β[1] route (0.0s) → selected: sum (Tool_MCP)
β[2] Tool:sum (1.2s) → "def quicksort(arr): ..."
β[3] think (3.1s) "代码结果..." → "代码已完成,调用 terminate"
β[4] route (0.0s) → selected: terminate (λx.x)
β[5] terminate (0.0s) → (identity: base case reached)
────────────────────────────────────────
Total: 5 β-reductions, 7.1s, ~2400 tokens
lambdagent repl — 交互式 REPL# 启动 REPL
lambdagent repl agent-config.yml
# 输出:
# lambdagent REPL v2.0
# Agent: SeeCoderManus (react, maxSteps=20)
# Lambda: Memory(Y₂₀(think >> route >> observe), redis)
# Type :help for commands, :quit to exit
#
# λ> 帮我写一个快速排序
# [β[0] think 2.8s] 需要调用代码工具...
# [β[1] Tool:sum 1.2s] def quicksort(arr): ...
# [β[2] think 3.1s] 代码完成,调用 terminate
# [β[3] terminate 0.0s] (base case)
#
# Result: def quicksort(arr): ...
# (4 β-reductions, 7.1s)
#
# λ> 能不能加上注释?
# [Memory: injecting 1 previous exchange]
# [β[0] think 2.5s] 用户想要注释版...
# ...
# REPL 内置命令:
# :help 帮助
# :quit / :q 退出
# :trace 显示上次执行的完整 β-规约链
# :trace N 显示第 N 步的详细信息
# :memory 显示当前 Memory 内容
# :memory clear 清空 Memory
# :lambda 显示当前 Agent 的 Lambda 表达式
# :lint 重新 lint 配置
# :reload 重新加载 YAML 配置(热更新)
# :model MODEL 切换模型
# :temp T 切换温度
# :tools 列出可用工具
# :tool NAME "input" 手动调用单个工具
# :export FILE 导出完整对话 + trace 到文件
# :stats 显示会话统计(总 β-规约数、总 token、总时间)
Lambda 语义:REPL = 持续的 β-规约环境。每次输入是一个新的函数应用 (agent input_n)。Memory 使得 Γ 在多次调用间累积——这正是 REPL 与单次 run 的区别。
REPL 的 Lambda 本质:
REPL session =
let Γ₀ = {} in
let (r₁, Γ₁) = agent(input₁) [Γ₀] in
let (r₂, Γ₂) = agent(input₂) [Γ₁] in
let (r₃, Γ₃) = agent(input₃) [Γ₂] in
...
每一轮:
1. 读取用户输入 xₙ
2. β-规约: (agent xₙ) [Γₙ₋₁] → (rₙ, Γₙ)
3. 打印 rₙ
4. 更新 Γₙ₋₁ → Γₙ (Memory 写入)
5. 循环
这就是 Y 组合子在 REPL 级别的又一次体现:
REPL = Y(λself.λΓ. let x = read() in let (r, Γ') = agent(x)[Γ] in print(r); self(Γ'))
lambdagent lint — 静态分析# Lint 单个文件
lambdagent lint agent-config.yml
# Lint 目录下所有配置
lambdagent lint configs/
# 选项:
# --level error|warn|info 最低报告级别
# --format text|json 输出格式
# --fix 自动修复可修复的问题
# --rules L001,L004 只运行指定规则
# --ignore L014 忽略指定规则
# 退出码:
# 0 = 无 error
# 1 = 有 error
# 2 = 配置文件不存在
lambdagent trace — 追踪查看/回放# 回放上次执行的 trace
lambdagent trace trace.json
# 选项:
# --step N 只看第 N 步
# --slow 逐步回放(按回车继续)
# --filter TERM 只看特定 Term 的 β-规约
# --timeline 时间线视图
# --flamegraph 火焰图输出(SVG)
--timeline 输出:
Time ──────────────────────────────────────────→
0s 2.8s 4.0s 7.1s 7.1s
│ │ │ │ │
├─think───┤ │ │ │
├─search──┤ │ │
├─think───┤ │
├─terminate
lambdagent lambda — 导出 Lambda 表达式# 导出为纯 Lambda 表达式
lambdagent lambda agent-config.yml
# 输出:
# Memory(
# Y₂₀(λself. λstate.
# let t = (λx. LLM_{qwen3-max, "你是SeeCoderManus..."}(x)) state in
# CASE (classify t) [
# ("sum", λx. MCP("example-mcp-server", "everything_get_sum", x)),
# ("improve", λx. MCP("example-mcp-server", "chat_improve_prompt", x)),
# ("terminate", λx. x)
# ] >> λobs.
# IF (obs = t) THEN t ELSE self(state ⊕ format(t, obs))
# ),
# Γ ∪ redis{size=20, ttl=7200}
# )
# 选项:
# --format human|formal|json 输出格式
# --desugar 展开所有语法糖到纯 λ/app/var
lambdagent serve — 启动服务# 启动 HTTP 服务
lambdagent serve agent-config.yml --port 8080
# 启动 MCP 服务器(让其他 Agent 作为工具调用本 Agent)
lambdagent serve agent-config.yml --mcp
# 启动 WebSocket 服务(流式输出)
lambdagent serve agent-config.yml --ws --port 8080
Lambda 语义:serve = 将 Agent 包装为一个持久运行的函数,等待外部应用(application)。
serve(agent, port) = Y(λself.λΓ.
let (x, conn) = accept(port) in ← 等待请求
let (r, Γ') = agent(x) [Γ] in ← β-规约
send(conn, r); ← 返回结果
self(Γ') ← 循环(保持 Memory)
)
lambdagent tools — 工具管理# 列出配置中的所有工具
lambdagent tools agent-config.yml
# 输出:
# Tools for SeeCoderManus:
# [MCP] everything_get_sum example-mcp-server https://ai-paas...
# [MCP] chat_improve_prompt example-mcp-server https://ai-paas...
# [Local] terminate (λx.x) base case
#
# MCP endpoints:
# example-mcp-server: https://your-mcp-endpoint.example.com/mcp/airouting
# Status: ✓ reachable (238ms)
# 测试单个工具
lambdagent tools agent-config.yml --test everything_get_sum "测试输入"
# 发现可用的 MCP 工具
lambdagent tools agent-config.yml --discover example-mcp-server
--tool)CLI 工具注入是 CLI 作为交互入口的核心差异化能力——它把任意 shell 命令变成 Lambda 项中的 Tool。
# 注入 shell 命令作为工具
lambdagent run agent.yml "分析日志" \
--tool grep="grep -c ERROR /var/log/app.log" \
--tool wc="wc -l /var/log/app.log" \
--tool curl="curl -s https://api.example.com/status"
# 注入管道命令
lambdagent run agent.yml "统计代码行数" \
--tool loc="find . -name '*.py' | xargs wc -l"
# 注入交互式命令(stdin 传参)
lambdagent run agent.yml "搜索文件" \
--tool search="grep -r {} src/"
Lambda 语义:
--tool grep="grep -c ERROR /var/log/app.log"
编译为:
Tool("grep", fn=lambda x: subprocess.run(
"grep -c ERROR /var/log/app.log",
shell=True, capture_output=True
).stdout.decode())
注入到 Agent 的工具集:
tools["grep"] = Tool("grep", shell_fn)
当命令中包含 {} 占位符时,Agent 的输出会被替换进去:
--tool search="grep -r {} src/"
编译为:
Tool("search", fn=lambda x: subprocess.run(
f"grep -r {shlex.quote(x)} src/",
shell=True, capture_output=True
).stdout.decode())
安全约束:
--tool 注入的命令只在用户明确指定时执行shlex.quote() 转义--tool-timeout 覆盖)rm -rf、dd、mkfs 等危险命令(黑名单)lambdagent CLI 遵循 Unix 管道哲学:每个命令读 stdin、写 stdout、错误写 stderr。
# 管道链: 编译检查 → 执行 → 后处理
lambdagent lint config.yml && \
lambdagent run config.yml "input" | jq '.result'
# Agent 链: 一个 Agent 的输出喂给另一个
lambdagent run summarizer.yml "长文本..." | \
lambdagent run translator.yml -
# 批量处理
cat inputs.txt | while read line; do
lambdagent run agent.yml "$line" --quiet
done > outputs.txt
# 与系统工具组合
curl -s https://api.example.com/data | \
lambdagent run analyzer.yml - | \
mail -s "分析报告" team@example.com
Lambda 语义:Unix 管道 | = 函数组合 >>。
cmd1 | cmd2 | cmd3
= cmd3(cmd2(cmd1(stdin)))
= (cmd1 >> cmd2 >> cmd3)(stdin)
= Compose(cmd1, cmd2, cmd3).apply(stdin)
这不是类比——这就是同一个数学结构。Unix shell 的管道和 lambdagent 的 >> 都是函数组合。CLI 是 Lambda 演算的自然栖息地。
# API Key
export ANTHROPIC_API_KEY=sk-...
export OPENAI_API_KEY=sk-...
export DASHSCOPE_API_KEY=sk-...
# 模型覆盖
export LAMBDAGENT_MODEL=claude-sonnet-4-20250514
export LAMBDAGENT_TEMPERATURE=0.0
export LAMBDAGENT_MAX_TOKENS=4096
# 追踪
export LAMBDAGENT_TRACE=1 # 默认开启 trace
export LAMBDAGENT_TRACE_FILE=trace.json # trace 输出路径
# MCP
export LAMBDAGENT_MCP_TIMEOUT=30 # MCP 调用超时
export LAMBDAGENT_MCP_RETRY=2 # MCP 重试次数
# Memory
export LAMBDAGENT_REDIS_URL=redis://localhost:6379
| 码 | 含义 | 场景 |
|---|---|---|
| 0 | 成功 | Agent 正常完成,lint 无 error |
| 1 | Agent 执行失败 | LLM API 错误、工具超时、Guard 失败 |
| 2 | 编译失败 | YAML 语法错误、Schema 不合法 |
| 3 | Lint 有 ERROR | lint 发现结构性问题 |
| 4 | 配置文件不存在 | 文件路径错误 |
| 130 | 用户中断 | Ctrl+C |
所有命令支持 --format 选项:
--format text(默认,人类可读):
Result: def quicksort(arr): ...
(4 β-reductions, 7.1s, ~2400 tokens)
--format json(机器可读,管道友好):
{
"result": "def quicksort(arr): ...",
"trace": [
{"step": 0, "term": "think", "duration_ms": 2800, "input": "...", "output": "..."},
{"step": 1, "term": "Tool:sum", "duration_ms": 1200, "input": "...", "output": "..."}
],
"stats": {
"total_steps": 4,
"total_time_ms": 7100,
"total_tokens": 2400
}
}
lambdagent/
├── __main__.py # python -m lambdagent 入口
├── cli/
│ ├── __init__.py
│ ├── main.py # argparse 路由
│ ├── compile_cmd.py # lambdagent compile
│ ├── run_cmd.py # lambdagent run
│ ├── repl_cmd.py # lambdagent repl
│ ├── lint_cmd.py # lambdagent lint
│ ├── trace_cmd.py # lambdagent trace
│ ├── lambda_cmd.py # lambdagent lambda
│ ├── serve_cmd.py # lambdagent serve
│ ├── tools_cmd.py # lambdagent tools
│ └── shell_tool.py # --tool 的 shell 命令包装
__main__.py 入口"""
python -m lambdagent <command> [args]
等价于: lambdagent <command> [args](通过 setup.py entry_points 注册)
"""
from lambdagent.cli.main import main
if __name__ == "__main__":
main()
"""
将 shell 命令包装为 lambdagent Tool。
--tool grep="grep -c ERROR /var/log/app.log"
→ Tool("grep", fn=ShellTool("grep -c ERROR /var/log/app.log"))
--tool search="grep -r {} src/"
→ Tool("search", fn=ShellTool("grep -r {} src/", parameterized=True))
"""
DANGEROUS_COMMANDS = {"rm -rf", "dd ", "mkfs", "format ", "> /dev/sd"}
class ShellTool:
def __init__(self, command: str, timeout: int = 30):
self.command = command
self.timeout = timeout
self.parameterized = "{}" in command
self._safety_check()
def _safety_check(self):
for dangerous in DANGEROUS_COMMANDS:
if dangerous in self.command:
raise ValueError(f"Dangerous command blocked: {self.command}")
def __call__(self, input_text: str) -> str:
if self.parameterized:
cmd = self.command.replace("{}", shlex.quote(str(input_text)))
else:
cmd = self.command
result = subprocess.run(
cmd, shell=True, capture_output=True, text=True,
timeout=self.timeout
)
if result.returncode != 0 and result.stderr:
return f"[ERROR] {result.stderr.strip()}"
return result.stdout.strip()
CLI 命令 调用的核心 API
───────── ──────────────
compile from_config(path) → term; describe_config(path)
run from_config(path) → term; term(input, ctx)
repl from_config(path) → term; while True: term(input, ctx)
lint lint_config(path) → issues
trace ctx.print_trace() / ctx.trace → json
lambda to_lambda_expr(path) → str [新增]
serve from_config(path) → term; http.serve(term)
tools _build_tools(cfg) → dict; ping endpoints
Agent 之间的通信不应只依赖 MCP。CLI(stdin/stdout)是最通用的进程间通信协议:
| = 函数组合 >>方式 协议 Lambda 语义 适用场景
───────── ───────── ───────────── ─────────
CLI Pipe stdin/stdout f >> g (Compose) 本机 Agent 链
MCP HTTP/SSE Tool(name, mcp_fn) 远程服务调用
CLI Tool 注入 subprocess Tool(name, shell_fn) 混合生态集成
# ═══ 新增: CLI 通信配置 ═══
cli:
# 本 Agent 作为 CLI 服务(被其他 Agent 调用)
server:
enabled: true
mode: pipe # "pipe" (stdin/stdout) | "socket" (Unix socket) | "tcp"
format: json # "text" | "json" | "jsonl" (一行一条)
socketPath: /tmp/lambdagent-myagent.sock # mode=socket 时
port: 0 # mode=tcp 时,0=随机端口
# 调用其他 CLI Agent
agents:
summarizer:
command: "python -m lambdagent run summarizer.yml -"
format: json
timeout: 60
retry: 2
translator:
command: "lambdagent run translator.yml --quiet -"
format: text
timeout: 30
legacy_tool:
command: "/usr/local/bin/legacy-analyzer" # 非 lambdagent 程序也行
format: text
timeout: 10
# 远程 Agent (通过 SSH)
remote_researcher:
command: "ssh gpu-server 'lambdagent run researcher.yml --quiet -'"
format: json
timeout: 120
# 管道链预设(快捷定义常用的 Agent 组合)
pipelines:
research_and_translate:
steps: [summarizer, translator] # 等价于 summarizer >> translator
analyze_with_review:
steps: [legacy_tool, summarizer]
parallel: false # 串行执行
# cli.agents 中的每个 Agent 编译为 Tool
# 但不是普通 Tool——是 "CLI Tool",通过 subprocess 调用
# YAML:
# cli:
# agents:
# summarizer:
# command: "lambdagent run summarizer.yml --quiet -"
# 编译为:
Tool("summarizer", fn=CLIAgent(
command="lambdagent run summarizer.yml --quiet -",
format="json",
timeout=60,
))
# Lambda 语义:
# summarizer = λx. exec("lambdagent run summarizer.yml --quiet -", x)
# 等价于: summarizer = λx. (from_config("summarizer.yml"))(x)
# 即: CLI 调用 = β-规约的跨进程版本
class CLIAgent:
"""
通过 CLI 调用另一个 Agent = 跨进程 β-规约
Lambda 语义:
CLIAgent(cmd) = λx. decode(exec(cmd, encode(x)))
通信协议:
1. 将 input 写入子进程的 stdin
2. 从子进程的 stdout 读取 output
3. stderr 用于日志/错误(不影响结果)
这就是 Unix 管道的语义——也是 Lambda 演算应用的语义:
(f x) 在 Lambda 中 = 把 x 喂给 f,拿到结果
cmd < input 在 Unix 中 = 把 input 喂给 cmd,拿到结果
"""
def __init__(self, command: str, format: str = "text", timeout: int = 60):
self.command = command
self.format = format
self.timeout = timeout
def __call__(self, input_text: str) -> str:
import subprocess
proc = subprocess.run(
self.command,
shell=True,
input=input_text,
capture_output=True,
text=True,
timeout=self.timeout,
)
if proc.returncode != 0:
return f"[CLI_ERROR:{proc.returncode}] {proc.stderr.strip()}"
output = proc.stdout.strip()
if self.format == "json":
import json
data = json.loads(output)
return data.get("result", output)
return output
# 方法 1: Unix 管道(最简单)
echo "长文本..." | \
lambdagent run summarizer.yml --quiet - | \
lambdagent run translator.yml --quiet -
# 方法 2: YAML 配置(可复用)
# config:
# cli.agents: {summarizer: ..., translator: ...}
# type: chain
# chain.steps 引用 cli.agents
lambdagent run pipeline.yml "长文本..."
# Lambda 语义完全相同:
# 方法 1: (translator ∘ summarizer)("长文本...")
# 方法 2: (translator >> summarizer)("长文本...")
# master-agent.yml
type: react
react: {maxSteps: 10}
mcp:
localTools: [terminate]
cli:
agents:
code_expert:
command: "lambdagent run code-agent.yml --quiet -"
math_expert:
command: "lambdagent run math-agent.yml --quiet -"
ReAct 执行:
β[0] think → "这个问题需要代码专家"
β[1] route → selected: code_expert (CLI Agent)
β[2] cli:code_expert → subprocess: lambdagent run code-agent.yml
↳ 子进程内部: β[0] think → β[1] ... → result
β[3] think → "代码结果看起来不错,terminate"
β[4] terminate → (base case)
cli:
agents:
# Python 脚本
data_fetcher:
command: "python scripts/fetch_data.py"
# Go 程序
fast_parser:
command: "./bin/parser --format json"
# Node.js 服务
renderer:
command: "node render.js"
# 任意 REST API (通过 curl)
api_call:
command: "curl -s -X POST https://api.example.com/process -d {}"
关键洞察:CLI 通信让 lambdagent 可以编排任何能读写 stdin/stdout 的程序——不限语言、不限框架、不限部署位置(SSH 透传)。这是 MCP 做不到的通用性。
维度 CLI Pipe MCP
────── ────────── ──────
协议 stdin/stdout HTTP/SSE
发现 手动配置 command 服务注册
延迟 低 (fork) 中 (HTTP)
流式 天然支持 (pipe) SSE
跨语言 任何程序 需 MCP SDK
跨机器 SSH 透传 HTTP
有状态 每次 fork 新进程 持久连接
调试 stderr + 退出码 HTTP 状态码
Lambda 语义 f >> g (Compose) Tool(name, fn)
from_config() 需要新增对 cli 字段的编译:
def _compile_cli_agents(cfg: dict) -> dict[str, Tool]:
"""编译 cli.agents 为 Tool 集合"""
cli_cfg = cfg.get("cli", {})
agents_cfg = cli_cfg.get("agents", {})
tools = {}
for name, agent_cfg in agents_cfg.items():
tools[name] = Tool(
name=f"cli:{name}",
fn=CLIAgent(
command=agent_cfg["command"],
format=agent_cfg.get("format", "text"),
timeout=agent_cfg.get("timeout", 60),
),
)
return tools
CLI Agent 和 MCP Tool 合并到同一个工具集中供 ReAct/Route 使用:
all_tools = {
**_compile_tools(cfg), # MCP 工具
**_compile_cli_agents(cfg), # CLI Agent 工具
}
| 测试 | 命令 | 期望 |
|---|---|---|
| C00 | lambdagent version |
打印版本信息 |
| C01 | lambdagent compile agent-cofig.yml |
打印 Lambda 结构,退出码 0 |
| C02 | lambdagent lint agent-cofig.yml |
输出 lint 结果,退出码 0(无 error) |
| C03 | lambdagent lint bad-config.yml |
退出码 3(有 error) |
| C04 | lambdagent run simple.yml "Hello" |
输出非空结果,退出码 0 |
| C05 | lambdagent run simple.yml "Hello" --trace |
输出含 β[0] 的 trace |
| C06 | lambdagent run simple.yml "Hello" --format json |
输出合法 JSON |
| C07 | echo "Hello" \| lambdagent run simple.yml - |
stdin 输入有效 |
| C08 | lambdagent run a.yml "x" --tool wc="wc -l f.txt" |
工具注入有效 |
| C09 | lambdagent lambda agent-cofig.yml |
输出 Lambda 表达式 |
| C10 | lambdagent tools agent-cofig.yml |
列出工具 + 状态 |
| C11 | lambdagent repl simple.yml 后输入 :quit |
正常退出 |
| C12 | lambdagent run a.yml "x" --tool rm="rm -rf /" |
被安全拦截 |
| C13 | echo "Hello" \| lambdagent run a.yml --quiet - \| lambdagent run b.yml - |
Agent 链管道 |
| C14 | CLI Agent 配置 cli.agents.sub |
编译为 Tool("cli:sub", CLIAgent(...)) |
| C15 | lambdagent tools config.yml 含 CLI Agent |
列出 MCP + CLI 工具 |
以下字段对应 lambdagent v2 新增的模块。它们是可选的顶级配置块。
# ═══ GroupChat 配置(type=groupchat 时使用)═══
groupchat:
agents: # 参与对话的 Agent 列表
- name: string
systemPrompt: string
model: object # 可选模型覆盖
maxRounds: int # 最大轮数(Y 组合子展开上界),默认 10
scheduler: string # "round_robin" | "random" | "llm"
schedulerPrompt: string # scheduler=llm 时的分类 prompt
termination: # 终止条件
keywords: [string] # 包含这些关键词时终止,默认 ["CONSENSUS", "DONE"]
custom: string # Python 表达式 (state, round) → bool
summaryAgent: # 可选的总结 Agent
systemPrompt: string
model: object
编译目标:
GroupChat(
agents=[Lam(a1), Lam(a2), ...],
max_rounds=10,
scheduler="round_robin" | Term(schedulerPrompt),
termination=fn,
summary_agent=Lam(summaryPrompt)
)
# ═══ SharedMemory 配置(多 Agent 共享状态)═══
sharedMemory:
enabled: bool # 是否启用
store: # 初始共享数据
key1: value1
key2: value2
appendOnly: bool # true = 类型安全模式(Σ' ⊇ Σ)
编译目标:
SharedMemory(store={"key1": "value1"}, append_only=True)
→ sm.wrap(agent) # 将 Agent 绑定到共享记忆
# ═══ Channel 配置(Agent 间通信)═══
channels:
- name: string # 通道名称
capacity: int # 缓冲区大小,0=无缓冲(同步),默认 0
编译目标:
channels = {name: Channel(name, capacity) for ch in config.channels}
# ═══ MCP Server 配置(v2: 结构化 MCP 连接)═══
mcpServers:
- name: string # 服务器名称
transport: string # "http" | "stdio"
url: string # transport=http 时的 URL
command: string # transport=stdio 时的命令
args: [string] # transport=stdio 时的参数
env: # transport=stdio 时的环境变量
KEY: VALUE
headers: # transport=http 时的 HTTP 头
Authorization: string
timeout: float # 超时秒数,默认 30
tools: [string] # 只暴露这些工具(空=全部),可选
编译目标:
server = MCPServer.http(url, headers) | MCPServer.stdio(command, args, env)
tools = server.to_tools() # 或 [server.to_tool(name) for name in config.tools]
# ═══ Handoff 配置(动态委派)═══
handoff:
selector: # 选择器
prompt: string # LLM 分类器 prompt
model: object # 可选模型覆盖
registry: # Agent 注册表
<name>: # 目标 Agent 名称
type: string
systemPrompt: string
# ... 子 agent 完整配置
fallback: # 兜底 Agent(可选)
systemPrompt: string
编译目标:
Handoff(
selector=Lam(selectorPrompt),
registry={name: compile(sub_agent) for ...},
fallback=Lam(fallbackPrompt)
)
# ═══ Skill 配置(可复用技能)═══
skills:
- name: string # 技能名称
description: string # 自然语言描述
tags: [string] # 标签
inputType: string # 输入类型描述,默认 "Str"
outputType: string # 输出类型描述,默认 "Str"
agent: # 技能实现
type: string
systemPrompt: string
# ... 完整 agent 配置
examples: # 使用示例
- input: string
output: string
编译目标:
Skill(
name=name, term=compile(agent_config),
description=description,
signature=SkillSignature(inputType, outputType),
tags=tags, examples=[(inp, out), ...]
)
# ═══ Checkpoint 配置(状态持久化)═══
checkpoint:
enabled: bool # 是否启用自动 checkpoint
directory: string # checkpoint 目录路径
maxCheckpoints: int # 最多保留多少个,默认 10
autoSaveSteps: int # 每 N 步 β-规约自动保存,0=不自动保存
编译目标:在 Runtime 中注入 CheckpointManager(directory, max_checkpoints)。
# ═══ A2A Protocol 配置(Agent 间协议)═══
a2a:
server: # 发布为 A2A 服务器(可选)
port: int # 监听端口,默认 8000
host: string # 监听地址,默认 "0.0.0.0"
clients: # 远程 A2A Agent(可选)
- name: string # 本地名称
url: string # 远程 A2A endpoint URL
timeout: float # 超时秒数,默认 60
编译目标:
# 远程 Agent 封装为本地 Term
remote_agents = {c.name: A2AClient(c.url, timeout=c.timeout) for c in config.a2a.clients}
# 可注入 Handoff / Route 的 registry
| 级别 | 字段 | Lambda 语义 | 编译行为 |
|---|---|---|---|
| 必须 | type, systemPrompt |
Agent 结构 + λ body | 缺失则报编译错误 |
| 核心 | model, react, mcp |
计算单元 + Y 参数 + Oracle | 缺失则用默认值 |
| 增强 | memory, guard, chain, router, parallel |
环境扩展 + 类型约束 + 组合 | 缺失则不包裹 |
| 多智能体 | groupchat, sharedMemory, channels, handoff |
π-演算扩展 | 缺失则不启用 |
| 协议 | mcpServers, a2a, skills |
MCP + A2A + Skill 系统 | 缺失则不启用 |
| 持久化 | checkpoint, rag |
状态保存 + 检索增强 | 缺失则不启用 |
| 安全 | sandbox |
进程隔离 + 资源限制 | 缺失则不启用 |
| 元数据 | agentId, name, description |
不影响 Lambda 语义 | 只用于标识和追踪 |
sandbox:
enabled: true # 是否启用沙箱(默认 false)
timeout: 30 # CPU 超时(秒),对应 RLIMIT_CPU
memory_mb: 256 # 内存上限(MB),对应 RLIMIT_AS
network: false # 是否允许网络访问
allow_subprocess: false # 是否允许创建子进程(RLIMIT_NPROC)
max_output_bytes: 65536 # 最大输出字节数
max_fds: 64 # 最大文件描述符数(RLIMIT_NOFILE)
policy: default # 预设策略: strict | default | permissive
当指定 policy 时,其余字段作为覆盖值(override)。未指定的字段使用预设默认值。
| 字段 | strict |
default |
permissive |
|---|---|---|---|
timeout |
5 | 30 | 300 |
memory_mb |
64 | 256 | 2048 |
network |
false | false | true |
allow_subprocess |
false | false | true |
max_output_bytes |
4096 | 65536 | 1048576 |
max_fds |
8 | 64 | 256 |
# sandbox.enabled = true 时:
from lambdagent import SandboxPolicy, SecureExecutor
if config.sandbox.policy:
policy = getattr(SandboxPolicy, config.sandbox.policy)()
else:
policy = SandboxPolicy(
timeout=config.sandbox.timeout,
memory_mb=config.sandbox.memory_mb,
network=config.sandbox.network,
allow_subprocess=config.sandbox.allow_subprocess,
max_output_bytes=config.sandbox.max_output_bytes,
max_fds=config.sandbox.max_fds,
)
# 字段级覆盖(policy 为基础,YAML 字段覆盖)
if config.sandbox.timeout is not None:
policy.timeout = config.sandbox.timeout
# ...
executor = SecureExecutor(policy=policy)
term = executor.sandbox_all_tools(term) # 递归包裹所有 Tool
Sandbox 不改变 Lambda 语义。编译后的 Term 树类型不变:
⟦sandbox: {enabled: true, policy: P}⟧ =
map(λt. SandboxedTool(t.name, t.fn, P), Tools(term))
所有 Tool 节点被替换为 SandboxedTool,但 SandboxedTool <: Tool,Term 树结构不变。