资源:给智能体注入上下文
工具让模型"做事",资源则解决"模型不知道背景"的问题:把文件、日志、文档以标准 URI 暴露给客户端,由客户端按需读取并注入对话。本章讲 URI 形式、注册与读取,以及注入机制。
资源模型:URI 寻址的只读数据
每个资源有一个 URI 与元数据(名称、mimeType)。常用形态:file:/// 指本地文件,log:// 指日志,doc:// 指文档,也允许自定义 scheme(如 mysql://、jira://)。客户端先 list 再按需 read,模型本身不会"主动读"资源。
{"jsonrpc": "2.0", "id": 1, "method": "resources/list"}
{"jsonrpc": "2.0", "id": 2, "method": "resources/read",
"params": {"uri": "file:///logs/app.log"}}
{"jsonrpc": "2.0", "id": 2, "result": {"contents": [
{"uri": "file:///logs/app.log", "mimeType": "text/plain",
"text": "10:00:01 INFO 服务启动完成"}]}}
用 FastMCP 暴露资源
字符串返回值按文本处理,bytes 按二进制处理,mimeType 自动推断:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("docs-server")
@mcp.resource("file:///guide/start.md")
def start_guide() -> str:
"""返回入门文档(静态资源:URI 固定)"""
return "# 使用说明\n本服务暴露内部文档与日志……"
@mcp.resource("log://app/{date}")
def daily_log(date: str) -> str:
"""返回指定日期的应用日志,例如 log://app/2026-01-01"""
with open(f"logs/{date}.log", encoding="utf-8") as f:
return f.read()
第二个例子是资源模板:URI 花括号里的 date 会自动绑定成函数参数,客户端填好参数就能 read,无需为每天写死一个资源。
上下文注入:客户端说了算
资源的读取由"应用控制(application-controlled)":
- 客户端向服务器取 resources/list 与资源模板列表,了解"有什么";
- 结合当前任务决定读哪个 URI(可能由模型先提一句"我需要日志");
- read 成功后,把文本作为上下文拼进发给模型的对话;
- 资源有更新时,客户端可订阅变更通知(订阅机制见官方规范)。
# 示意:客户端把读到的资源文本作为 user 消息注入
messages = [
{"role": "system", "content": "你是运维助手,依据日志回答问题。"},
{"role": "user", "content": "请分析今天 10 点的报错:\n" + log_text},
]
实用模式:文件系统服务器
最典型的实践是"文件即资源":暴露目录让客户端按 URI 读任意允许的文件,配合模板做到"给路径就返回内容"。注意权限边界要严格收紧,别把敏感目录暴露给模型,安全细节见后续安全章节。
小结
资源用 URI 表达"可读的背景信息",静态资源与模板资源覆盖固定与动态两类;注入与否由客户端决定。什么时候选资源而不是工具?内容只读、给模型看——选资源。下一章是最后一种原语:提示词模板与工作流。