写 Agent 应用时最耗时间的往往不是提示词,而是胶水代码:MCP 服务器怎么接、几个 Agent 怎么串起来、想换个模型对比效果要不要改代码、端到端测试怎么做。fast-agent 把这几件事收敛成一层声明式语法:你用装饰器描述「有哪些 Agent、各自挂哪些 MCP 服务器、彼此怎么编排」,运行、流式输出、工具循环、日志与模型切换都交给框架。它是少数把 MCP 的 Sampling 与 Elicitation 也完整支持并端到端测过的框架,支持图片与 PDF 这类多模态内容,还能把你调好的 Agent 反过来暴露成一个 MCP 服务器给别人调用。本教程从装 uv 开始,跑通单 Agent、接上 MCP 服务器、用五种编排模式搭工作流、处理多模态与人工确认,最后把它变成可对外提供能力的服务。
Step 1:装 uv 与 fast-agent,先跑一个交互会话
fast-agent 走 Python 生态,推荐用 uv 安装,避免污染系统解释器。装好之后先不要写代码,用 fast-agent go 起一个交互式会话确认三件事:命令行工具在 PATH 里、模型密钥能被读到、模型能正常返回。这一步通过再往下走,能省掉后面大量「到底是框架问题还是密钥问题」的排查时间。go 后面可以直接跟远程 MCP 服务器地址、模型名或已安装的卡片包,用来快速试工具与模型的搭配。
# 1) 装 uv(官方安装脚本,详见 docs.astral.sh/uv)
curl -LsSf https://astral.sh/uv/install.sh | sh # Linux / macOS
# Windows(PowerShell):
# powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# 2) 装 fast-agent 命令行工具
uv tool install fast-agent-mcp
# 机器上有多个 Python 版本时显式指定,避免装到旧解释器上
uv tool install fast-agent-mcp --python 3.13.5
# 3) 起一个交互式会话,确认能跑
fast-agent go # 默认模型,直接开聊
fast-agent go --url https://hf.co/mcp # 直接连一个远程 MCP 服务器试工具
fast-agent go --model=generic.qwen2.5 # 用 Ollama 上的本地模型
fast-agent go --pack hf-dev # 用已安装或市场里的卡片包
还有一个目录约定值得先知道:fast-agent 会从当前目录开始向上递归查找配置文件,所以你可以在项目根目录放一份 fastagent.config.yaml,下面的子目录里跑命令都会读到它。团队协同时这点很有用——一份配置、一套 MCP 服务器,所有人跑出来的工具集是一致的。
密钥不要进版本库:模型密钥写在 secrets 文件里而不是 config 文件里,并确保它已被 .gitignore 覆盖;config 是要提交的,secrets 不是。仓库里出现过密钥就当作已泄露处理,去服务商后台轮换,而不是只补一次 .gitignore。
Step 2:写一个最小 Agent,并学会不改代码换模型
定义 Agent 的最小形态只需要一条 instruction,剩下的样板代码是固定的:建一个 FastAgent 应用、用 @fast.agent 声明 Agent、在 async with fast.run() 里发消息或开交互会话。把它存成 .py 文件用 uv run 跑起来即可。这个设计的价值在于「提示词即配置」——提示词留在文件里,能评审、能 diff、能版本管理,而不是散落在某次聊天记录里。
import asyncio
from fast_agent import FastAgent
# 创建一个 Agent 应用
fast = FastAgent("Agent Example")
@fast.agent(
instruction="Given an object, respond only with an estimate of its size."
)
async def main():
async with fast.run() as agent:
# 发一条消息,拿到结果
moon_size = await agent("the moon")
print(moon_size)
# 也可以开一个交互式会话,边聊边调
# await agent.interactive()
if __name__ == "__main__":
asyncio.run(main())
换模型不需要改代码,用命令行开关即可:uv run sizer.py --model sonnet 这样一行就能把同一个 Agent 换到另一个模型上跑。这个能力在调试阶段极其好用——同一个流程分别在强模型与便宜模型上跑一遍,你能立刻看出是哪一步开始掉链子,而不是笼统地觉得「模型不行」。如果要把 Agent 嵌进脚本,加 --quiet 只返回最终结果,输出干净便于管道处理。
Step 3:把 MCP 服务器挂到指定的 Agent 上
MCP 服务器统一在 fastagent.config.yaml 里声明,Agent 通过 servers 参数点名要用哪几个。这个「按 Agent 分派」的粒度很重要:工具数量直接影响模型选对工具的概率与冷启动耗时,让摘要 Agent 只挂抓取服务器、让写作 Agent 一个工具都不挂,比把所有工具开给所有 Agent 稳得多。
# fastagent.config.yaml
mcp:
servers:
fetch:
command: "uvx"
args: ["mcp-server-fetch"]
filesystem:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/project"]
@fast.agent(
"url_fetcher",
"Given a URL, provide a complete and comprehensive summary",
servers=["fetch"], # 对应上面 config 里的服务器名
)
@fast.agent(
"social_media",
"""Write a 280 character social media post for any given text.
Respond only with the post, never use hashtags.""",
)
@fast.chain(
name="post_writer",
sequence=["url_fetcher", "social_media"],
)
async def main():
async with fast.run() as agent:
await agent.post_writer("http://llmindset.co.uk")
跑起来是 uv run workflow/chaining.py;也可以用 --agent 指定跑哪一个组件、用 --message 直接给输入,方便写进脚本或 CI。官方的 quickstart 命令(fast-agent quickstart workflow)会直接生成一批示例,覆盖 Anthropic《Building Effective Agents》里的几种模式,还包含一个带评估优化闭环的 Researcher Agent 与一个演示 MCP Roots 的数据分析 Agent,建议先照着跑一遍再自己写。
Windows 用户注意:官方说明里提到,Filesystem 与 Docker 两个 MCP 服务器在 Windows 上需要额外的配置改动,相关说明写在你生成的配置文件注释里,照着改即可。另外工具越多不等于能力越强:一次挂上几十个工具,模型选错工具的概率会明显上升,冷启动也会变慢。
Step 4:用五种编排模式把 Agent 组成工作流
工作流是 fast-agent 的主场,五种模式用一行装饰器切换。chain 是串行管道,前一个的输出是后一个的输入,适合「先抓后写」这类固定两步;parallel 把同一条消息扇出给多个 Agent 同时处理,适合翻译、多视角评审这些彼此独立的分支;router 让模型判断该交给哪个 Agent,适合入口不确定、各分支成本差异大的场景;evaluator_optimizer 由生成器与评估器组成闭环,直到评估达到指定等级或达到打磨次数上限;maker 重复采样同一个工作 Agent,直到某个答案拿到 k 票优势,用多次采样换稳定性。
@fast.chain(name="post_writer", sequence=["url_fetcher", "social_media"])
@fast.parallel(name="translate", fan_out=["translate_fr", "translate_de", "translate_es"])
@fast.router(name="route", agents=["agent1", "agent2", "agent3"])
@fast.evaluator_optimizer(
name="researcher",
generator="web_searcher",
evaluator="quality_assurance",
min_rating="EXCELLENT",
max_refinements=3, # 硬上限,防止无限打磨烧钱
)
@fast.maker(
name="reliable_classifier",
worker="classifier",
k=3, # 需要拿到的票数优势
max_samples=25, # 采样硬上限
)
选择顺序建议是「能用 chain 说清楚的不要上 router」。router 的收益是省成本,代价是路由错了整条链都错,而且错得悄无声息;evaluator_optimizer 与 maker 的收益是质量,代价是调用次数成倍增长——它们一定要配上 max_refinements 与 max_samples 这类上限参数,否则一次跑偏就是一张意料之外的账单。上线前先用小样本跑一遍,把单次任务的调用次数与耗时记下来,再决定要不要放量。
Step 5:多模态、结构化输出与向人要信息
多模态是这个框架的既有能力:图片与 PDF 可以作为提示词、资源以及 MCP 工具调用的结果直接进入流程,不需要你自己先把 PDF 转成文本再喂进去。对下游代码来说,更有用的是结构化输出——把 Agent 的输出约定成固定结构,就能直接交给程序处理,不必再用正则去抠自然语言里的字段。具体写法以官方文档对应章节为准,别凭印象猜参数。
@fast.agent(
"invoice_reader",
"从发票里提取金额、开票日期与供应商,字段不全就说明缺哪个。",
servers=["filesystem"],
)
async def main():
async with fast.run() as agent:
# 结果文件里带遥测,便于横向对比不同模型的表现
data = await agent.invoice_reader.send(
"读取 /Users/you/invoices/2026-10.pdf 并提取字段"
)
print(data)
还有一类场景值得单独提:需要人拍板时,Agent 可以反过来向你要信息,而不是自己猜一个继续跑。这对应 MCP 的 Elicitation 能力,也是 fast-agent 官方强调的完整支持项之一。典型用法是「找到三个候选航班,让我选一个再下单」——把决策点显式留给人,流程的可靠性会高一个量级,尤其是涉及付款、发信、删数据这类不可逆动作时。
不可逆动作必须留人工闸门:不管框架支持得多好,涉及付款、对外发信、删除数据、修改生产配置的操作,都要让 Agent 先给出计划、等人确认再执行。把「先问再做」写进 instruction,比事后回滚便宜得多。
Step 6:把你的 Agent 暴露成一个 MCP 服务器
最后一步是反向暴露:任何一个 Agent 或工作流都能通过传输参数切成服务端模式,对外提供 MCP 接口。这意味着你调好的「读发票」或「写周报」流程,不用再复制粘贴提示词给同事,让他们把你的服务当工具接上就行。对外提供 HTTP 传输时,官方还提供了传输诊断能力,用于检查 Streamable HTTP 的用法是否规范——这类细节在自建网关或代理后面尤其容易出问题。
# 1) 以服务端模式跑起来(--transport 会自动切到 server 模式)
uv run agent.py --transport http --port 8001
# 2) 客户端侧接入(以 Claude Code 为例,其余支持 MCP 的客户端同理)
claude mcp add --transport http my-agent http://127.0.0.1:8001/mcp
# 3) 批量跑评估:--quiet 只输出最终结果,便于写进脚本与 CI
uv run workflow/chaining.py --agent post_writer --message "" --quiet > out.txt
收尾三件事。一是把暴露出去的工具集收敛到最小,只留必要工具,写操作全部走人工确认。二是善用内置遥测:结果文件里带调用与耗时数据,把它留下来做回归对比,比凭感觉判断「这次好像变慢了」靠谱。三是别忘了版本——提示词、config、工作流定义都在文件里,是最适合进版本库的一类资产,改动要有评审记录。
暴露服务等于开放工具权限:把 Agent 暴露成 MCP 服务器之后,任何能访问该端点的人都能驱动你的工具与密钥。至少做到:只绑本机回环或置于鉴权之后、只挂必要工具、写操作人工确认、不要把对外服务与你的主密钥放在同一进程环境里。
常见问题速查
| 现象 | 原因与处理 |
|---|---|
| 提示找不到配置文件 | 从当前目录向上递归查找;确认文件在命令执行目录或其父目录 |
| 模型调用报密钥错误 | 密钥写在 secrets 文件里或走环境变量;确认没被 .gitignore 的文件提交过 |
| Agent 用不上某个工具 | 检查 config 里 mcp.servers 的名字与 Agent 的 servers 列表是否一致 |
| Windows 上 filesystem / docker 服务器起不来 | 官方生成的配置文件里有 Windows 需要的改动注释,照着改 |
| 想对比模型又不想改代码 | 用 --model 开关,同一份代码跑多个模型 |
| 输出太长没法接管道 | 加 --quiet 只保留最终结果 |
| --server 参数报错 | 已被官方标记弃用,改用 --transport |
| 并行工作流很慢 | 每个分支都是一次完整模型调用,成本与耗时叠加;先用小样本验证 |
| 评估优化闭环停不下来 | 给 evaluator_optimizer 设 max_refinements 硬上限,给 maker 设 max_samples |