feat:优化执行步骤
This commit is contained in:
+23
-34
@@ -1,44 +1,33 @@
|
||||
"""skill 渐进式加载:目录追加到系统提示,正文和附件由模型用 read_file 按需读取
|
||||
"""skill 正文直接写进系统提示
|
||||
|
||||
加载、解析和校验都由 Deep Agents 的 SkillsMiddleware 完成,这里只有配置
|
||||
skill 总共几 KB,每次调用都会命中提示缓存;如果让模型自己 read_file,每个请求要多 2 次串行调用,
|
||||
每次几秒,比多带这几 KB 贵得多。需要附件(references/)的 skill 出现后,再改回按需读取
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from deepagents.backends.filesystem import FilesystemBackend
|
||||
from deepagents.middleware.filesystem import FilesystemMiddleware
|
||||
from deepagents.middleware.skills import SkillsMiddleware
|
||||
from langchain.agents.middleware import AgentMiddleware
|
||||
|
||||
SKILLS_ROOT = Path(__file__).resolve().parents[2] / "skills"
|
||||
|
||||
# 必须保留三个占位符;目录每一行的格式由库固定
|
||||
SKILLS_PROMPT = """<skills>
|
||||
以下 skill 提供特定任务的做法。{skills_locations}{skills_load_warnings}
|
||||
|
||||
{skills_list}
|
||||
|
||||
使用方式:
|
||||
1. 任务符合某个 skill 的描述时,先用 read_file 读取它的 SKILL.md 再动手,传 limit=1000(默认只读 100 行)
|
||||
2. 正文中引用的文件写的是相对路径,拼在该 skill 的目录后再读取,例如 chart-replace 正文里的 references/a.md 要读 /chart-replace/references/a.md
|
||||
3. 一个请求可以用到多个 skill
|
||||
</skills>"""
|
||||
def _split_frontmatter(text: str) -> tuple[dict[str, str], str]:
|
||||
_, header, body = text.split("---", 2)
|
||||
meta = {}
|
||||
for line in header.strip().splitlines():
|
||||
key, _, value = line.partition(":")
|
||||
meta[key.strip()] = value.strip()
|
||||
return meta, body.strip()
|
||||
|
||||
|
||||
def skill_middleware(root: Path = SKILLS_ROOT) -> list[AgentMiddleware]:
|
||||
# virtual_mode:路径以 skills/ 为根,拦截 ..、~ 和根目录以外的路径
|
||||
backend = FilesystemBackend(root_dir=root, virtual_mode=True)
|
||||
return [
|
||||
FilesystemMiddleware(
|
||||
backend=backend,
|
||||
# 只开放读取,不提供写入、搜索和执行
|
||||
tools=["read_file"],
|
||||
# 关闭大结果写盘,否则会往 skills/ 里写文件
|
||||
tool_token_limit_before_evict=None,
|
||||
human_message_token_limit_before_evict=None,
|
||||
),
|
||||
# 用元组写明来源标签,裸路径 "/" 的标签会变成 Unnamed
|
||||
SkillsMiddleware(
|
||||
backend=backend, sources=[("/", "大屏")], system_prompt=SKILLS_PROMPT
|
||||
),
|
||||
]
|
||||
def skills_prompt(root: Path = SKILLS_ROOT) -> str:
|
||||
"""每个 skill 一段:description 说明什么时候用,正文是做法;任务符合描述时按正文做,一个请求可以用到多个"""
|
||||
sections = []
|
||||
for path in sorted(root.glob("*/SKILL.md")):
|
||||
meta, body = _split_frontmatter(path.read_text(encoding="utf-8"))
|
||||
sections.append(
|
||||
f'<skill name="{meta["name"]}">\n适用:{meta["description"]}\n\n{body}\n</skill>'
|
||||
)
|
||||
return (
|
||||
"<skills>\n以下 skill 提供特定任务的做法,任务符合“适用”时按正文做,一个请求可以用到多个\n\n"
|
||||
+ "\n\n".join(sections)
|
||||
+ "\n</skills>"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user