概述
本指南展示了如何使用深度智能体构建内容创作智能体。该智能体能加载品牌语调和技能,将研究任务委托给子智能体,根据加载的技能起草博客或社交媒体内容,并通过Gemini生成配套图片。 您构建的智能体将实现以下功能:- 从品牌指令和技能文件夹加载语调和工作流规则
- 将网络研究委托给具有
web_search能力的专用子智能体 - 根据加载的技能起草博客或社交媒体内容
- 使用Gemini生成封面或社交媒体图片并保存至项目目录
核心概念
本教程涵盖以下内容:- 品牌指令(通过Managed Deep Agents的上下文,或SDK的记忆文件)定义的持续生效的语调和研究规则
- 技能用于博客和社交媒体的运营手册
- 子智能体用于写作前的研究
- SDK路径下的文件系统后端实现文件读写
- 自定义工具用于搜索和图像生成
先决条件
API密钥:- Anthropic(Claude)或其他聊天模型供应商
- Google(Gemini)用于使用
gemini-2.5-flash-image的图像生成 - Tavily(免费版)用于网络搜索
- LangSmith用于追踪(SDK路径下可选,托管深度智能体场景必需)
选择您的路径
从托管深度智能体开始运行无需维护基础设施的生产级智能体。或者,在保持与深度智能体框架兼容的前提下,使用深度智能体SDK自行托管智能体,或运行自定义LangSmith部署。- Managed Deep Agents
- Deep Agents SDK
托管深度智能体目前处于 公开的 beta 版本,部署于 LangSmith Cloud。
instructions.md,技能文件位于skills/,在代码中声明工具和研究者子智能体。图像工具在mda dev期间将文件写入项目目录。配置
要开始,你需要::::python- Python 和
uv。 :::
- Node.js 和 npm。 :::
- 向你的模型服务提供商申请的 API 密钥。
1
创建项目
:::python::::::js:::
uvx --from managed-deepagents mda init content-builder
cd content-builder
npx managed-deepagents init content-builder
cd content-builder
pnpm dlx managed-deepagents init content-builder
cd content-builder
bunx managed-deepagents init content-builder
cd content-builder
2
添加 API 密钥
将聊天、图像、搜索和LangSmith密钥添加至
.env:.env
ANTHROPIC_API_KEY=<ANTHROPIC_API_KEY>
GOOGLE_API_KEY=<GOOGLE_API_KEY>
TAVILY_API_KEY=<TAVILY_API_KEY>
LANGSMITH_API_KEY=<LANGSMITH_API_KEY>
GOOGLE_API_KEY密钥对于Gemini图像生成(即使使用Claude作为聊天模型)也是必需的。不要将
.env文件提交至版本控制。该文件包含敏感信息。3
安装依赖项
:::python::::::js:::
uv add tavily-python google-genai pillow
npm install tavily @google/generative-ai zod
pnpm add tavily @google/generative-ai zod
bun add tavily @google/generative-ai zod
构建智能体
1
添加工具
创建搜索和图像工具。Markdown研究笔记使用智能体文件系统(※ 重要提示:在您之前的输出中占位符集不正确。缺少的 id:[‘0’];意外的额外 id:[]。请再次翻译全文,并保持每个占位符(六边形括号 + 数字)的原位置,且仅出现一次。::::::js
创建:::
write_file)。封面和社交媒体图片在本地mda dev期间通过宿主机写入项目目录。:::python
创建tools/content.py:tools/content.py
import os
from pathlib import Path
from typing import Literal
from langchain.tools import tool
# Project root (parent of tools/)
PROJECT_DIR = Path(__file__).resolve().parent.parent
@tool
def web_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news"] = "general",
) -> dict:
"""Search the web for current information.
Args:
query: The search query (be specific and detailed)
max_results: Number of results to return (default: 5)
topic: "general" for most queries, "news" for current events
Returns:
Search results with titles, URLs, and content excerpts.
"""
try:
from tavily import TavilyClient
api_key = os.environ.get("TAVILY_API_KEY")
if not api_key:
return {"error": "TAVILY_API_KEY not set"}
client = TavilyClient(api_key=api_key)
return client.search(query, max_results=max_results, topic=topic)
except Exception as e:
return {"error": f"Search failed: {e}"}
@tool
def generate_cover(prompt: str, slug: str) -> str:
"""Generate a cover image for a blog post.
Args:
prompt: Detailed description of the image to generate.
slug: Blog post slug. Image saves to blogs/<slug>/hero.png
"""
try:
from google import genai
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.5-flash-image",
contents=[prompt],
)
for part in response.parts:
if part.inline_data is not None:
image = part.as_image()
output_path = PROJECT_DIR / "blogs" / slug / "hero.png"
output_path.parent.mkdir(parents=True, exist_ok=True)
image.save(str(output_path))
return f"Image saved to {output_path}"
return "No image generated"
except Exception as e:
return f"Error: {e}"
@tool
def generate_social_image(prompt: str, platform: str, slug: str) -> str:
"""Generate an image for a social media post.
Args:
prompt: Detailed description of the image to generate.
platform: Either "linkedin" or "tweets"
slug: Post slug. Image saves to <platform>/<slug>/image.png
"""
try:
from google import genai
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.5-flash-image",
contents=[prompt],
)
for part in response.parts:
if part.inline_data is not None:
image = part.as_image()
output_path = PROJECT_DIR / platform / slug / "image.png"
output_path.parent.mkdir(parents=True, exist_ok=True)
image.save(str(output_path))
return f"Image saved to {output_path}"
return "No image generated"
except Exception as e:
return f"Error: {e}"
tools/content.ts:tools/content.ts
import { tool } from "@langchain/core/tools";
import * as z from "zod";
import * as fs from "node:fs";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
const PROJECT_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
export const webSearch = tool(
async ({ query, maxResults = 5, topic = "general" }) => {
const apiKey = process.env.TAVILY_API_KEY;
if (!apiKey) return { error: "TAVILY_API_KEY not set" };
try {
const { TavilyClient } = await import("tavily");
const client = new TavilyClient({ apiKey });
return client.search(query, { maxResults, topic });
} catch (e) {
return { error: `Search failed: ${e}` };
}
},
{
name: "web_search",
description: "Search the web for current information.",
schema: z.object({
query: z.string().describe("The search query (be specific and detailed)"),
maxResults: z
.number()
.optional()
.describe("Number of results to return (default: 5)"),
topic: z
.enum(["general", "news"])
.optional()
.describe('"general" for most queries, "news" for current events'),
}),
},
);
export const generateCover = tool(
async ({ prompt, slug }) => {
try {
const { GoogleGenerativeAI } = await import("@google/generative-ai");
const genai = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY ?? "");
const model = genai.getGenerativeModel({
model: "gemini-2.5-flash-image",
});
const result = await model.generateContent(prompt);
const part = result.response.candidates?.[0]?.content?.parts?.find(
(p) => p.inlineData,
);
if (!part?.inlineData) return "No image generated";
const outputPath = path.join(PROJECT_DIR, "blogs", slug, "hero.png");
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, Buffer.from(part.inlineData.data, "base64"));
return `Image saved to ${outputPath}`;
} catch (e) {
return `Error: ${e}`;
}
},
{
name: "generate_cover",
description: "Generate a cover image for a blog post.",
schema: z.object({
prompt: z
.string()
.describe("Detailed description of the image to generate."),
slug: z
.string()
.describe("Blog post slug. Image saves to blogs/<slug>/hero.png"),
}),
},
);
export const generateSocialImage = tool(
async ({ prompt, platform, slug }) => {
try {
const { GoogleGenerativeAI } = await import("@google/generative-ai");
const genai = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY ?? "");
const model = genai.getGenerativeModel({
model: "gemini-2.5-flash-image",
});
const result = await model.generateContent(prompt);
const part = result.response.candidates?.[0]?.content?.parts?.find(
(p) => p.inlineData,
);
if (!part?.inlineData) return "No image generated";
const outputPath = path.join(PROJECT_DIR, platform, slug, "image.png");
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, Buffer.from(part.inlineData.data, "base64"));
return `Image saved to ${outputPath}`;
} catch (e) {
return `Error: ${e}`;
}
},
{
name: "generate_social_image",
description: "Generate an image for a social media post.",
schema: z.object({
prompt: z
.string()
.describe("Detailed description of the image to generate."),
platform: z.string().describe('Either "linkedin" or "tweets"'),
slug: z
.string()
.describe("Post slug. Image saves to <platform>/<slug>/image.png"),
}),
},
);
2
添加品牌指令
将始终生效的品牌语调和研究要求存放在部署时,托管深度智能体会将这些指令同步至上下文中心。
instructions.md。托管深度智能体将此文件作为主智能体系统的系统提示(这是SDK的AGENTS.md / memory=角色,而非持久化记忆):# Content Writer Agent
You are a content writer for a technology company. Your job is to create engaging, informative content that educates readers about AI, software development, and emerging technologies.
## Brand Voice
- **Professional but approachable**: Write like a knowledgeable colleague, not a textbook
- **Clear and direct**: Avoid jargon unless necessary; explain technical concepts simply
- **Confident but not arrogant**: Share expertise without being condescending
- **Engaging**: Use concrete examples, analogies, and stories to illustrate points
## Writing Standards
1. **Use active voice**: "The agent processes requests" not "Requests are processed by the agent"
2. **Lead with value**: Start with what matters to the reader, not background
3. **One idea per paragraph**: Keep paragraphs focused and scannable
4. **Concrete over abstract**: Use specific examples, numbers, and case studies
5. **End with action**: Every piece should leave the reader knowing what to do next
## Content Pillars
Our content focuses on:
- AI agents and automation
- Developer tools and productivity
- Software architecture and best practices
- Emerging technologies and trends
## Formatting Guidelines
- Use headers (H2, H3) to break up long content
- Include code examples where relevant (with syntax highlighting)
- Add bullet points for lists of 3+ items
- Keep sentences under 25 words when possible
- Include a clear call-to-action at the end
## Research Requirements
Before writing on any topic:
1. Use the `researcher` subagent for in-depth topic research
2. Gather at least 3 credible sources
3. Identify the key points readers need to understand
4. Find concrete examples or case studies to illustrate concepts
3
添加技能
Create a Create
skills/ directory. Each skill is a folder with a SKILL.md. Managed Deep Agents 会自动发现技能;你不需要传递 skills= 参数。Create skills/blog-post/SKILL.md:---
name: blog-post
description: Writes and structures long-form blog posts, creates tutorial outlines, and optimizes content for SEO with cover image generation. Use when the user asks to write a blog post, article, how-to guide, tutorial, technical writeup, thought leadership piece, or long-form content.
---
# Blog Post Writing Skill
## Research First (Required)
**Before writing any blog post, you MUST delegate research:**
1. Use the `task` tool with `subagent_type: "researcher"`
2. In the description, specify BOTH the topic AND where to save:
```
task(
subagent_type="智能体",
description="研究 [主题]。将研究结果保存到 research/[slug].md"
)
```
Example:
```
task(
subagent_type="智能体",
description="研究 2025 年 AI 智能体的现状。将研究结果保存到 research/ai-agents-2025.md"
)
```
3. After research completes, read the findings file before writing
## Output Structure (Required)
**Every blog post MUST have both a post AND a cover image:**
```
blogs/
└── <slug>/
├── post.md # 博客文章内容
└── hero.png # REQUIRED: 生成的封面图片
```
Example: A post about "AI Agents in 2025" → `blogs/ai-agents-2025/`
**You MUST complete both steps:**
1. Write the post to `blogs/<slug>/post.md`
2. Generate a cover image using `generate_image` and save to `blogs/<slug>/hero.png`
**A blog post is NOT complete without its cover image.**
## Blog Post Structure
Every blog post should follow this structure:
### 1. Hook (Opening)
- Start with a compelling question, statistic, or statement
- Make the reader want to continue
- Keep it to 2-3 sentences
### 2. Context (The Problem)
- Explain why this topic matters
- Describe the problem or opportunity
- Connect to the reader's experience
### 3. Main Content (The Solution)
- Break into 3-5 main sections with H2 headers
- Each section covers one key point
- Include code examples, diagrams, or screenshots where helpful
- Use bullet points for lists
### 4. Practical Application
- Show how to apply the concepts
- Include step-by-step instructions if applicable
- Provide code snippets or templates
### 5. Conclusion & CTA
- Summarize key takeaways (3 bullets max)
- End with a clear call-to-action
- Link to related resources
## Cover Image Generation
After writing the post, generate a cover image using the `generate_cover` tool:
```
generate_cover(prompt="图片的详细描述...", slug="your-blog-slug")
```
The tool saves the image to `blogs/<slug>/hero.png`.
### Writing Effective Image Prompts
Structure your prompt with these elements:
1. **Subject**: What is the main focus? Be specific and concrete.
2. **Style**: Art direction (minimalist, isometric, flat design, 3D render, watercolor, etc.)
3. **Composition**: How elements are arranged (centered, rule of thirds, symmetrical)
4. **Color palette**: Specific colors or mood (warm earth tones, cool blues and purples, high contrast)
5. **Lighting/Atmosphere**: Soft diffused light, dramatic shadows, golden hour, neon glow
6. **Technical details**: Aspect ratio considerations, negative space for text overlay
### Example Prompts
**For a technical blog post:**
```
等距 3D 插画,展示相互连接的发光立方体代表 AI 智能体,每个立方体都有微妙的电路图案。立方体通过发光的数据流连接。深海军蓝背景 (#0a192f) 配合亮蓝色 (#64ffda) 和柔和紫色 (#c792ea) 的点缀。简洁极简风格,顶部留出大量空白用于标题。专业科技美学。
```
**For a tutorial/how-to:**
```
简洁平面插画,展示双手在键盘上打字,抽象代码符号向上漂浮,转化为灯泡和齿轮。背景为从柔和珊瑚到浅桃色的渐变色。友好、亲切的风格。居中构图,留出文本叠加空间。
```
**For thought leadership:**
```
抽象可视化,展示人形剪影与几何神经网络图案融合。分割构图 - 左侧为有机水彩纹理,右侧过渡到干净矢量线条。柔和的橄榄绿和温暖陶土色系。沉思、前瞻的氛围。
```
## SEO Considerations
- Include the main keyword in the title and first paragraph
- Use the keyword naturally 3-5 times throughout
- Keep the title under 60 characters
- Write a meta description (150-160 characters)
## Quality Checklist
Before finishing:
- [ ] Post saved to `blogs/<slug>/post.md`
- [ ] Hero image generated at `blogs/<slug>/hero.png`
- [ ] Hook grabs attention in first 2 sentences
- [ ] Each section has a clear purpose
- [ ] Conclusion summarizes key points
- [ ] CTA tells reader what to do next
skills/social-media/SKILL.md:---
name: social-media
description: Drafts engaging social media posts, writes hooks, suggests hashtags, creates thread structures, and generates companion images. Use when the user asks to write a LinkedIn post, tweet, Twitter/X thread, social media caption, social post, or repurpose content for social platforms.
---
# Social Media Content Skill
## Research First (Required)
**Before writing any social media content, you MUST delegate research:**
1. Use the `task` tool with `subagent_type: "researcher"`
2. In the description, specify BOTH the topic AND where to save:
```
task(
subagent_type="研究者",
description="研究[TOPIC]。将发现保存到research/[slug].md"
)
```
Example:
```
task(
subagent_type="研究者",
description="研究2025年可再生能源趋势。将发现保存到research/renewable-energy.md"
)
```
3. After research completes, read the findings file before writing
## Output Structure (Required)
**Every social media post MUST have both content AND an image:**
**LinkedIn posts:**
```
linkedin/
└── <slug>/
├── post.md # 帖子内容
└── image.png # REQUIRED: 生成的视觉元素
```
**Twitter/X threads:**
```
tweets/
└── <slug>/
├── thread.md # 帖子内容
└── image.png # REQUIRED: 生成的视觉元素
```
Example: A LinkedIn post about "prompt engineering" → `linkedin/prompt-engineering/`
**You MUST complete both steps:**
1. Write the content to the appropriate path
2. Generate an image using `generate_image` and save alongside the post
**A social media post is NOT complete without its image.**
## Platform Guidelines
### LinkedIn
**Format:**
- 1,300 character limit (show more after ~210 chars)
- First line is crucial - make it hook
- Use line breaks for readability
- 3-5 hashtags at the end
**Tone:**
- Professional but personal
- Share insights and learnings
- Ask questions to drive engagement
- Use "I" and share experiences
**Structure:**
```
[钩子 - 1句引人入胜的话]
[空行]
[背景 - 为什么这很重要]
[空行]
[主要见解 - 2-3段简短段落]
[空行]
[号召行动或问题]
#hashtag1 #hashtag2 #hashtag3
```
### Twitter/X
**Format:**
- 280 character limit per tweet
- Threads for longer content (use 1/🧵 format)
- No more than 2 hashtags per tweet
**Thread Structure:**
```
1/🧵 [钩子 - 主要见解]
2/ [支持点1]
3/ [支持点2]
4/ [示例或证据]
5/ [结论+号召行动]
```
## Image Generation
Every social media post needs an eye-catching image. Use the `generate_social_image` tool:
```
generate_social_image(prompt="详细描述...", platform="linkedin", slug="your-post-slug")
```
The tool saves the image to `<platform>/<slug>/image.png`.
### Social Image Best Practices
Social images need to work at small sizes in crowded feeds:
- **Bold, simple compositions** - one clear focal point
- **High contrast** - stands out when scrolling
- **No text in image** - too small to read, platforms add their own
- **Square or 4:5 ratio** - works across platforms
### Writing Effective Prompts
Include these elements:
1. **Single focal point**: One clear subject, not a busy scene
2. **Bold style**: Vibrant colors, strong shapes, high contrast
3. **Simple background**: Solid color, gradient, or subtle texture
4. **Mood/energy**: Match the post tone (inspiring, urgent, thoughtful)
### Example Prompts
**For an insight/tip post:**
```
一个发光的灯泡悬浮在深紫色渐变背景上,灯泡由相互连接的金色几何线条构成,向外散发柔和的光线。极简、引人注目、高对比度。方形构图。
```
**For announcements/news:**
```
由彩色几何形状组成的抽象火箭船向上发射,留下粒子轨迹。明亮珊瑚色和蓝绿色调,背景为干净白色。充满活力、庆祝氛围。大胆扁平插画风格。
```
**For thought-provoking content:**
```
两个重叠的半透明圆圈,一个蓝色一个橙色,在中心形成发光的交集。代表合作或想法的交集。深煤灰背景,柔和空灵的光芒。极简和沉思。
```
## Content Types
### Announcement Posts
- Lead with the news
- Explain the impact
- Include link or next step
### Insight Posts
- Share one specific learning
- Explain the context briefly
- Make it actionable
### Question Posts
- Ask a genuine question
- Provide your take first
- Keep it focused on one topic
## Quality Checklist
Before finishing:
- [ ] Post saved to `linkedin/<slug>/post.md` or `tweets/<slug>/thread.md`
- [ ] Image generated alongside the post
- [ ] First line hooks attention
- [ ] Content fits platform limits
- [ ] Tone matches platform norms
- [ ] Has clear CTA or question
- [ ] Hashtags are relevant (not generic)
4
创建智能体
用下面的完整文件替换脚手架生成的智能体入口。它会创建一个带有图像工具和内联研究者子智能体(使用 ::::::js
替换 ※ 重要提示:在您之前的输出中占位符集不正确。缺少的 id:[‘0’];意外的额外 id:[]。请再次翻译全文,并保持每个占位符(六边形括号 + 数字)的原位置,且仅出现一次。:::
web_search)的智能体。技能和指令来自项目文件。:::python
替换 agent.py:agent.py
from managed_deepagents import define_deep_agent
from tools.content import generate_cover, generate_social_image, web_search
researcher = {
"name": "researcher",
"description": (
"ALWAYS use this first to research any topic before writing content. "
"Searches the web for current information, statistics, and sources. "
"When delegating, tell it the topic AND the file path to save results "
"(e.g., 'Research renewable energy and save to research/renewable-energy.md')."
),
"model": "anthropic:claude-haiku-4-5-20251001",
"system_prompt": """You are a research assistant. You have access to web_search and write_file tools.
## Your Tools
- web_search(query, max_results=5, topic="general") - Search the web
- write_file(file_path, content) - Save your findings
## Your Process
1. Use web_search to find information on the topic
2. Make 2-3 targeted searches with specific queries
3. Gather key statistics, quotes, and examples
4. Save findings to the file path specified in your task
## Important
- The user will tell you WHERE to save the file - use that exact path
- Always include source URLs in your findings
- Keep findings concise but informative
""",
"tools": [web_search],
}
agent = define_deep_agent(
name="content-builder",
model="anthropic:claude-sonnet-4-5-20250929",
tools=[generate_cover, generate_social_image],
subagents=[researcher],
)
agent.ts:agent.ts
import { defineDeepAgent } from "managed-deepagents";
import {
generateCover,
generateSocialImage,
webSearch,
} from "./tools/content";
const researcher = {
name: "researcher",
description:
"ALWAYS use this first to research any topic before writing content. " +
"Searches the web for current information, statistics, and sources. " +
"When delegating, tell it the topic AND the file path to save results " +
"(e.g., 'Research renewable energy and save to research/renewable-energy.md').",
model: "anthropic:claude-haiku-4-5-20251001",
systemPrompt: `You are a research assistant. You have access to web_search and write_file tools.
## Your Tools
- web_search(query, max_results=5, topic="general") - Search the web
- write_file(file_path, content) - Save your findings
## Your Process
1. Use web_search to find information on the topic
2. Make 2-3 targeted searches with specific queries
3. Gather key statistics, quotes, and examples
4. Save findings to the file path specified in your task
## Important
- The user will tell you WHERE to save the file - use that exact path
- Always include source URLs in your findings
- Keep findings concise but informative
`,
tools: [webSearch],
};
export const agent = defineDeepAgent({
name: "content-builder",
model: "anthropic:claude-sonnet-4-5-20250929",
tools: [generateCover, generateSocialImage],
subagents: [researcher],
});
运行智能体
1
本地运行
:::python::::::js:::你应该会看到智能体加载技能、委托给
uv sync
uv run mda dev
npm install
npx mda dev
pnpm install
pnpm exec mda dev
bun install
bunx mda dev
mda dev 会在 LangSmith Studio 中打开智能体。发送类似下面的提示词:Write a blog post about how AI agents are transforming software development
researcher、编写 Markdown 并调用图像工具。更多信息请参阅 使用 LangSmith Studio 进行本地开发。2
部署(可选)
:::python::::::js:::See Deploy.
uv run mda deploy
npx mda deploy
pnpm exec mda deploy
bunx mda deploy
当你希望自行托管智能体或运行自定义 LangSmith 部署 时,请使用开源 SDK。该示例将行为保存在记忆文件、技能和子智能体定义中,并额外使用 FilesystemBackend。在你自己的项目中将 ::::::js添加 ::::::python
从项目目录调用智能体时,既可省略参数,也可通过参数传递提示词:::::::js
从项目目录执行:通过额外参数传递提示词::::当路径遵循
设置
:::python1
创建项目目录
mkdir content-builder-agent
cd content-builder-agent
2
安装依赖项
pip install deepagents google-genai pillow pyyaml rich tavily-python langchain
uv init
uv add deepagents google-genai pillow pyyaml rich tavily-python langchain
uv sync
deepagents 固定到受支持的版本范围(例如 >=0.3.5,<0.4.0),以与上游示例保持一致。3
设置 API 密钥
export ANTHROPIC_API_KEY="your_anthropic_api_key"
export GOOGLE_API_KEY="your_google_api_key"
export TAVILY_API_KEY="your_tavily_api_key" # Optional
export LANGSMITH_API_KEY="your_langsmith_api_key" # Optional
1
创建项目目录
mkdir content-builder-agent
cd content-builder-agent
2
安装依赖项
npm install deepagents @langchain/core @langchain/anthropic @google/generative-ai tavily zod tsx
yarn add deepagents @langchain/core @langchain/anthropic @google/generative-ai tavily zod tsx
tsx 以运行 content_writer.ts。安装 @langchain/anthropic,以便 LangChain 加载 createDeepAgent 使用的默认 Claude 模型。3
设置 API 密钥
export ANTHROPIC_API_KEY="your_anthropic_api_key"
export GOOGLE_API_KEY="your_google_api_key"
export TAVILY_API_KEY="your_tavily_api_key" # Optional
export LANGSMITH_API_KEY="your_langsmith_api_key" # Optional
添加配置文件
1
添加 AGENTS.md
在项目根目录创建 要匹配你自己的语调、内容支柱和格式规则,请更新
AGENTS.md。当你在创建智能体时通过 记忆 参数传入此文件,它会被加载到系统提示词中,使品牌语调和研究期望在每次运行中生效:# Content Writer Agent
You are a content writer for a technology company. Your job is to create engaging, informative content that educates readers about AI, software development, and emerging technologies.
## Brand Voice
- **Professional but approachable**: Write like a knowledgeable colleague, not a textbook
- **Clear and direct**: Avoid jargon unless necessary; explain technical concepts simply
- **Confident but not arrogant**: Share expertise without being condescending
- **Engaging**: Use concrete examples, analogies, and stories to illustrate points
## Writing Standards
1. **Use active voice**: "The agent processes requests" not "Requests are processed by the agent"
2. **Lead with value**: Start with what matters to the reader, not background
3. **One idea per paragraph**: Keep paragraphs focused and scannable
4. **Concrete over abstract**: Use specific examples, numbers, and case studies
5. **End with action**: Every piece should leave the reader knowing what to do next
## Content Pillars
Our content focuses on:
- AI agents and automation
- Developer tools and productivity
- Software architecture and best practices
- Emerging technologies and trends
## Formatting Guidelines
- Use headers (H2, H3) to break up long content
- Include code examples where relevant (with syntax highlighting)
- Add bullet points for lists of 3+ items
- Keep sentences under 25 words when possible
- Include a clear call-to-action at the end
## Research Requirements
Before writing on any topic:
1. Use the `researcher` subagent for in-depth topic research
2. Gather at least 3 credible sources
3. Identify the key points readers need to understand
4. Find concrete examples or case studies to illustrate concepts
AGENTS.md。2
添加 subagents.yaml
创建 创建深度智能体时会传入该文件。
subagents.yaml。它描述了一个 researcher 子智能体,带有由 Tavily 支持的 web_search 工具:subagents.yaml
# Subagent definitions
# These are loaded by content_writer.py and wired up with tools
researcher:
description: >
ALWAYS use this first to research any topic before writing content.
Searches the web for current information, statistics, and sources.
When delegating, tell it the topic AND the file path to save results
(e.g., 'Research renewable energy and save to research/renewable-energy.md').
model: anthropic:claude-haiku-4-5-20251001
system_prompt: |
You are a research assistant. You have access to web_search and write_file tools.
## Your Tools
- web_search(query, max_results=5, topic="general") - Search the web
- write_file(file_path, content) - Save your findings
## Your Process
1. Use web_search to find information on the topic
2. Make 2-3 targeted searches with specific queries
3. Gather key statistics, quotes, and examples
4. Save findings to the file path specified in your task
## Important
- The user will tell you WHERE to save the file - use that exact path
- Always include source URLs in your findings
- Keep findings concise but informative
tools:
- web_search
3
添加技能
创建一个 Create 它们指示智能体先调用
skills/ 目录。每个技能都是一个文件夹,其中包含带有 YAML frontmatter(name、description)和指令的 SKILL.md 文件。Create skills/blog-post/SKILL.md:---
name: blog-post
description: Writes and structures long-form blog posts, creates tutorial outlines, and optimizes content for SEO with cover image generation. Use when the user asks to write a blog post, article, how-to guide, tutorial, technical writeup, thought leadership piece, or long-form content.
---
# Blog Post Writing Skill
## Research First (Required)
**Before writing any blog post, you MUST delegate research:**
1. Use the `task` tool with `subagent_type: "researcher"`
2. In the description, specify BOTH the topic AND where to save:
```
task(
subagent_type="智能体",
description="研究 [主题]。将研究结果保存到 research/[slug].md"
)
```
Example:
```
task(
subagent_type="智能体",
description="研究 2025 年 AI 智能体的现状。将研究结果保存到 research/ai-agents-2025.md"
)
```
3. After research completes, read the findings file before writing
## Output Structure (Required)
**Every blog post MUST have both a post AND a cover image:**
```
blogs/
└── <slug>/
├── post.md # 博客文章内容
└── hero.png # REQUIRED: 生成的封面图片
```
Example: A post about "AI Agents in 2025" → `blogs/ai-agents-2025/`
**You MUST complete both steps:**
1. Write the post to `blogs/<slug>/post.md`
2. Generate a cover image using `generate_image` and save to `blogs/<slug>/hero.png`
**A blog post is NOT complete without its cover image.**
## Blog Post Structure
Every blog post should follow this structure:
### 1. Hook (Opening)
- Start with a compelling question, statistic, or statement
- Make the reader want to continue
- Keep it to 2-3 sentences
### 2. Context (The Problem)
- Explain why this topic matters
- Describe the problem or opportunity
- Connect to the reader's experience
### 3. Main Content (The Solution)
- Break into 3-5 main sections with H2 headers
- Each section covers one key point
- Include code examples, diagrams, or screenshots where helpful
- Use bullet points for lists
### 4. Practical Application
- Show how to apply the concepts
- Include step-by-step instructions if applicable
- Provide code snippets or templates
### 5. Conclusion & CTA
- Summarize key takeaways (3 bullets max)
- End with a clear call-to-action
- Link to related resources
## Cover Image Generation
After writing the post, generate a cover image using the `generate_cover` tool:
```
generate_cover(prompt="图片的详细描述...", slug="your-blog-slug")
```
The tool saves the image to `blogs/<slug>/hero.png`.
### Writing Effective Image Prompts
Structure your prompt with these elements:
1. **Subject**: What is the main focus? Be specific and concrete.
2. **Style**: Art direction (minimalist, isometric, flat design, 3D render, watercolor, etc.)
3. **Composition**: How elements are arranged (centered, rule of thirds, symmetrical)
4. **Color palette**: Specific colors or mood (warm earth tones, cool blues and purples, high contrast)
5. **Lighting/Atmosphere**: Soft diffused light, dramatic shadows, golden hour, neon glow
6. **Technical details**: Aspect ratio considerations, negative space for text overlay
### Example Prompts
**For a technical blog post:**
```
等距 3D 插画,展示相互连接的发光立方体代表 AI 智能体,每个立方体都有微妙的电路图案。立方体通过发光的数据流连接。深海军蓝背景 (#0a192f) 配合亮蓝色 (#64ffda) 和柔和紫色 (#c792ea) 的点缀。简洁极简风格,顶部留出大量空白用于标题。专业科技美学。
```
**For a tutorial/how-to:**
```
简洁平面插画,展示双手在键盘上打字,抽象代码符号向上漂浮,转化为灯泡和齿轮。背景为从柔和珊瑚到浅桃色的渐变色。友好、亲切的风格。居中构图,留出文本叠加空间。
```
**For thought leadership:**
```
抽象可视化,展示人形剪影与几何神经网络图案融合。分割构图 - 左侧为有机水彩纹理,右侧过渡到干净矢量线条。柔和的橄榄绿和温暖陶土色系。沉思、前瞻的氛围。
```
## SEO Considerations
- Include the main keyword in the title and first paragraph
- Use the keyword naturally 3-5 times throughout
- Keep the title under 60 characters
- Write a meta description (150-160 characters)
## Quality Checklist
Before finishing:
- [ ] Post saved to `blogs/<slug>/post.md`
- [ ] Hero image generated at `blogs/<slug>/hero.png`
- [ ] Hook grabs attention in first 2 sentences
- [ ] Each section has a clear purpose
- [ ] Conclusion summarizes key points
- [ ] CTA tells reader what to do next
skills/social-media/SKILL.md:---
name: social-media
description: Drafts engaging social media posts, writes hooks, suggests hashtags, creates thread structures, and generates companion images. Use when the user asks to write a LinkedIn post, tweet, Twitter/X thread, social media caption, social post, or repurpose content for social platforms.
---
# Social Media Content Skill
## Research First (Required)
**Before writing any social media content, you MUST delegate research:**
1. Use the `task` tool with `subagent_type: "researcher"`
2. In the description, specify BOTH the topic AND where to save:
```
task(
subagent_type="研究者",
description="研究[TOPIC]。将发现保存到research/[slug].md"
)
```
Example:
```
task(
subagent_type="研究者",
description="研究2025年可再生能源趋势。将发现保存到research/renewable-energy.md"
)
```
3. After research completes, read the findings file before writing
## Output Structure (Required)
**Every social media post MUST have both content AND an image:**
**LinkedIn posts:**
```
linkedin/
└── <slug>/
├── post.md # 帖子内容
└── image.png # REQUIRED: 生成的视觉元素
```
**Twitter/X threads:**
```
tweets/
└── <slug>/
├── thread.md # 帖子内容
└── image.png # REQUIRED: 生成的视觉元素
```
Example: A LinkedIn post about "prompt engineering" → `linkedin/prompt-engineering/`
**You MUST complete both steps:**
1. Write the content to the appropriate path
2. Generate an image using `generate_image` and save alongside the post
**A social media post is NOT complete without its image.**
## Platform Guidelines
### LinkedIn
**Format:**
- 1,300 character limit (show more after ~210 chars)
- First line is crucial - make it hook
- Use line breaks for readability
- 3-5 hashtags at the end
**Tone:**
- Professional but personal
- Share insights and learnings
- Ask questions to drive engagement
- Use "I" and share experiences
**Structure:**
```
[钩子 - 1句引人入胜的话]
[空行]
[背景 - 为什么这很重要]
[空行]
[主要见解 - 2-3段简短段落]
[空行]
[号召行动或问题]
#hashtag1 #hashtag2 #hashtag3
```
### Twitter/X
**Format:**
- 280 character limit per tweet
- Threads for longer content (use 1/🧵 format)
- No more than 2 hashtags per tweet
**Thread Structure:**
```
1/🧵 [钩子 - 主要见解]
2/ [支持点1]
3/ [支持点2]
4/ [示例或证据]
5/ [结论+号召行动]
```
## Image Generation
Every social media post needs an eye-catching image. Use the `generate_social_image` tool:
```
generate_social_image(prompt="详细描述...", platform="linkedin", slug="your-post-slug")
```
The tool saves the image to `<platform>/<slug>/image.png`.
### Social Image Best Practices
Social images need to work at small sizes in crowded feeds:
- **Bold, simple compositions** - one clear focal point
- **High contrast** - stands out when scrolling
- **No text in image** - too small to read, platforms add their own
- **Square or 4:5 ratio** - works across platforms
### Writing Effective Prompts
Include these elements:
1. **Single focal point**: One clear subject, not a busy scene
2. **Bold style**: Vibrant colors, strong shapes, high contrast
3. **Simple background**: Solid color, gradient, or subtle texture
4. **Mood/energy**: Match the post tone (inspiring, urgent, thoughtful)
### Example Prompts
**For an insight/tip post:**
```
一个发光的灯泡悬浮在深紫色渐变背景上,灯泡由相互连接的金色几何线条构成,向外散发柔和的光线。极简、引人注目、高对比度。方形构图。
```
**For announcements/news:**
```
由彩色几何形状组成的抽象火箭船向上发射,留下粒子轨迹。明亮珊瑚色和蓝绿色调,背景为干净白色。充满活力、庆祝氛围。大胆扁平插画风格。
```
**For thought-provoking content:**
```
两个重叠的半透明圆圈,一个蓝色一个橙色,在中心形成发光的交集。代表合作或想法的交集。深煤灰背景,柔和空灵的光芒。极简和沉思。
```
## Content Types
### Announcement Posts
- Lead with the news
- Explain the impact
- Include link or next step
### Insight Posts
- Share one specific learning
- Explain the context briefly
- Make it actionable
### Question Posts
- Ask a genuine question
- Provide your take first
- Keep it focused on one topic
## Quality Checklist
Before finishing:
- [ ] Post saved to `linkedin/<slug>/post.md` or `tweets/<slug>/thread.md`
- [ ] Image generated alongside the post
- [ ] First line hooks attention
- [ ] Content fits platform limits
- [ ] Tone matches platform norms
- [ ] Has clear CTA or question
- [ ] Hashtags are relevant (not generic)
researcher 子智能体,将 Markdown 写入 blogs/、linkedin/ 或 tweets/,并调用 generate_cover 或 generate_social_image 生成图像。构建脚本
:::python 在项目根目录创建content_writer.py。以下各部分应按顺序放在同一个文件中。
::::::js
在项目根目录创建 content_writer.ts。以下各部分应按顺序放在同一个文件中。
:::1
添加工具
:::python
研究者子智能体使用 Tavily 搜索。博客和社交媒体工作流使用 Gemini 图像生成。稍后创建智能体时,::::::js
研究者使用 Tavily 搜索。博客和社交媒体工作流使用 Google Generative AI SDK 进行图像生成。:::
load_subagents 会读取 subagents.yaml 并将工具名称解析为这些函数。import os
from pathlib import Path
from typing import Literal
import yaml
from langchain.tools import tool
EXAMPLE_DIR = Path(__file__).parent
@tool
def web_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news"] = "general",
) -> dict:
"""Search the web for current information.
Args:
query: The search query (be specific and detailed)
max_results: Number of results to return (default: 5)
topic: "general" for most queries, "news" for current events
Returns:
Search results with titles, URLs, and content excerpts.
"""
try:
from tavily import TavilyClient
api_key = os.environ.get("TAVILY_API_KEY")
if not api_key:
return {"error": "TAVILY_API_KEY not set"}
client = TavilyClient(api_key=api_key)
return client.search(query, max_results=max_results, topic=topic)
except Exception as e:
return {"error": f"Search failed: {e}"}
@tool
def generate_cover(prompt: str, slug: str) -> str:
"""Generate a cover image for a blog post.
Args:
prompt: Detailed description of the image to generate.
slug: Blog post slug. Image saves to blogs/<slug>/hero.png
"""
try:
from google import genai
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.5-flash-image",
contents=[prompt],
)
for part in response.parts:
if part.inline_data is not None:
image = part.as_image()
output_path = EXAMPLE_DIR / "blogs" / slug / "hero.png"
output_path.parent.mkdir(parents=True, exist_ok=True)
image.save(str(output_path))
return f"Image saved to {output_path}"
return "No image generated"
except Exception as e:
return f"Error: {e}"
@tool
def generate_social_image(prompt: str, platform: str, slug: str) -> str:
"""Generate an image for a social media post.
Args:
prompt: Detailed description of the image to generate.
platform: Either "linkedin" or "tweets"
slug: Post slug. Image saves to <platform>/<slug>/image.png
"""
try:
from google import genai
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.5-flash-image",
contents=[prompt],
)
for part in response.parts:
if part.inline_data is not None:
image = part.as_image()
output_path = EXAMPLE_DIR / platform / slug / "image.png"
output_path.parent.mkdir(parents=True, exist_ok=True)
image.save(str(output_path))
return f"Image saved to {output_path}"
return "No image generated"
except Exception as e:
return f"Error: {e}"
def load_subagents(config_path: Path) -> list:
"""Load subagent definitions from YAML and wire up tools.
Unlike `memory` and `skills`, deep agents do not load subagents from files by default.
This helper externalizes configuration so you can edit YAML without changing Python code.
"""
available_tools = {
"web_search": web_search,
}
with open(config_path) as f:
config = yaml.safe_load(f)
subagents = []
for name, spec in config.items():
subagent = {
"name": name,
"description": spec["description"],
"system_prompt": spec["system_prompt"],
}
if "model" in spec:
subagent["model"] = spec["model"]
if "tools" in spec:
subagent["tools"] = [available_tools[t] for t in spec["tools"]]
subagents.append(subagent)
return subagents
import { tool } from "@langchain/core/tools";
import * as z from "zod";
import * as fs from "node:fs";
import * as path from "node:path";
const EXAMPLE_DIR = path.dirname(new URL(import.meta.url).pathname);
const webSearch = tool(
async ({ query, maxResults = 5, topic = "general" }) => {
const apiKey = process.env.TAVILY_API_KEY;
if (!apiKey) return { error: "TAVILY_API_KEY not set" };
try {
const { TavilyClient } = await import("tavily");
const client = new TavilyClient({ apiKey });
return client.search(query, { maxResults, topic });
} catch (e) {
return { error: `Search failed: ${e}` };
}
},
{
name: "web_search",
description: "Search the web for current information.",
schema: z.object({
query: z.string().describe("The search query (be specific and detailed)"),
maxResults: z
.number()
.optional()
.describe("Number of results to return (default: 5)"),
topic: z
.enum(["general", "news"])
.optional()
.describe('"general" for most queries, "news" for current events'),
}),
},
);
const generateCover = tool(
async ({ prompt, slug }) => {
try {
const { GoogleGenerativeAI } = await import("@google/generative-ai");
const genai = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY ?? "");
const model = genai.getGenerativeModel({
model: "gemini-2.5-flash-image",
});
const result = await model.generateContent(prompt);
const part = result.response.candidates?.[0]?.content?.parts?.find(
(p) => p.inlineData,
);
if (!part?.inlineData) return "No image generated";
const outputPath = path.join(EXAMPLE_DIR, "blogs", slug, "hero.png");
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, Buffer.from(part.inlineData.data, "base64"));
return `Image saved to ${outputPath}`;
} catch (e) {
return `Error: ${e}`;
}
},
{
name: "generate_cover",
description: "Generate a cover image for a blog post.",
schema: z.object({
prompt: z
.string()
.describe("Detailed description of the image to generate."),
slug: z
.string()
.describe("Blog post slug. Image saves to blogs/<slug>/hero.png"),
}),
},
);
const generateSocialImage = tool(
async ({ prompt, platform, slug }) => {
try {
const { GoogleGenerativeAI } = await import("@google/generative-ai");
const genai = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY ?? "");
const model = genai.getGenerativeModel({
model: "gemini-2.5-flash-image",
});
const result = await model.generateContent(prompt);
const part = result.response.candidates?.[0]?.content?.parts?.find(
(p) => p.inlineData,
);
if (!part?.inlineData) return "No image generated";
const outputPath = path.join(EXAMPLE_DIR, platform, slug, "image.png");
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, Buffer.from(part.inlineData.data, "base64"));
return `Image saved to ${outputPath}`;
} catch (e) {
return `Error: ${e}`;
}
},
{
name: "generate_social_image",
description: "Generate an image for a social media post.",
schema: z.object({
prompt: z
.string()
.describe("Detailed description of the image to generate."),
platform: z.string().describe('Either "linkedin" or "tweets"'),
slug: z
.string()
.describe("Post slug. Image saves to <platform>/<slug>/image.png"),
}),
},
);
2
创建智能体
:::python
创建深度智能体时,通过@[create_deep_agent]传递内存路径、技能目录、图像工具、子智能体定义(从YAML中传入),并配置以example目录为根的FilesystemBackend,以确保路径如::::::js
创建深度智能体时,通过@[createDeepAgent]传递内存路径、技能目录、图像工具、内联子智能体定义,并配置以example目录为根的FilesystemBackend,以确保路径如:::
./AGENTS.md和./skills/能正确解析。from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
def create_content_writer():
"""Create a content writer agent configured by filesystem files."""
return create_deep_agent(
model="google_genai:gemini-3.6-flash",
memory=["./AGENTS.md"],
skills=["./skills/"],
tools=[generate_cover, generate_social_image],
subagents=load_subagents(EXAMPLE_DIR / "subagents.yaml"),
backend=FilesystemBackend(root_dir=EXAMPLE_DIR),
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
def create_content_writer():
"""Create a content writer agent configured by filesystem files."""
return create_deep_agent(
model="openai:gpt-5.5",
memory=["./AGENTS.md"],
skills=["./skills/"],
tools=[generate_cover, generate_social_image],
subagents=load_subagents(EXAMPLE_DIR / "subagents.yaml"),
backend=FilesystemBackend(root_dir=EXAMPLE_DIR),
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
def create_content_writer():
"""Create a content writer agent configured by filesystem files."""
return create_deep_agent(
model="anthropic:claude-sonnet-5",
memory=["./AGENTS.md"],
skills=["./skills/"],
tools=[generate_cover, generate_social_image],
subagents=load_subagents(EXAMPLE_DIR / "subagents.yaml"),
backend=FilesystemBackend(root_dir=EXAMPLE_DIR),
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
def create_content_writer():
"""Create a content writer agent configured by filesystem files."""
return create_deep_agent(
model="openrouter:z-ai/glm-5.2",
memory=["./AGENTS.md"],
skills=["./skills/"],
tools=[generate_cover, generate_social_image],
subagents=load_subagents(EXAMPLE_DIR / "subagents.yaml"),
backend=FilesystemBackend(root_dir=EXAMPLE_DIR),
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
def create_content_writer():
"""Create a content writer agent configured by filesystem files."""
return create_deep_agent(
model="fireworks:accounts/fireworks/models/glm-5p2",
memory=["./AGENTS.md"],
skills=["./skills/"],
tools=[generate_cover, generate_social_image],
subagents=load_subagents(EXAMPLE_DIR / "subagents.yaml"),
backend=FilesystemBackend(root_dir=EXAMPLE_DIR),
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
def create_content_writer():
"""Create a content writer agent configured by filesystem files."""
return create_deep_agent(
model="baseten:zai-org/GLM-5.2",
memory=["./AGENTS.md"],
skills=["./skills/"],
tools=[generate_cover, generate_social_image],
subagents=load_subagents(EXAMPLE_DIR / "subagents.yaml"),
backend=FilesystemBackend(root_dir=EXAMPLE_DIR),
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
def create_content_writer():
"""Create a content writer agent configured by filesystem files."""
return create_deep_agent(
model="ollama:north-mini-code-1.0",
memory=["./AGENTS.md"],
skills=["./skills/"],
tools=[generate_cover, generate_social_image],
subagents=load_subagents(EXAMPLE_DIR / "subagents.yaml"),
backend=FilesystemBackend(root_dir=EXAMPLE_DIR),
)
./AGENTS.md和./skills/能正确解析。import { createDeepAgent, FilesystemBackend } from "deepagents";
function createContentWriter() {
const researcherSubagent = {
name: "researcher",
description:
"Research subagent with web search capability. Delegate research tasks here.",
systemPrompt:
"You are a research assistant. Use the web_search tool to find current, accurate information and return well-organized findings.",
tools: [webSearch],
};
return createDeepAgent({
model: "google:gemini-3.6-flash",
memory: ["./AGENTS.md"],
skills: ["./skills/"],
tools: [generateCover, generateSocialImage],
subagents: [researcherSubagent],
backend: new FilesystemBackend({ rootDir: EXAMPLE_DIR }),
});
}
import { createDeepAgent, FilesystemBackend } from "deepagents";
function createContentWriter() {
const researcherSubagent = {
name: "researcher",
description:
"Research subagent with web search capability. Delegate research tasks here.",
systemPrompt:
"You are a research assistant. Use the web_search tool to find current, accurate information and return well-organized findings.",
tools: [webSearch],
};
return createDeepAgent({
model: "openai:gpt-5.5",
memory: ["./AGENTS.md"],
skills: ["./skills/"],
tools: [generateCover, generateSocialImage],
subagents: [researcherSubagent],
backend: new FilesystemBackend({ rootDir: EXAMPLE_DIR }),
});
}
import { createDeepAgent, FilesystemBackend } from "deepagents";
function createContentWriter() {
const researcherSubagent = {
name: "researcher",
description:
"Research subagent with web search capability. Delegate research tasks here.",
systemPrompt:
"You are a research assistant. Use the web_search tool to find current, accurate information and return well-organized findings.",
tools: [webSearch],
};
return createDeepAgent({
model: "anthropic:claude-sonnet-5",
memory: ["./AGENTS.md"],
skills: ["./skills/"],
tools: [generateCover, generateSocialImage],
subagents: [researcherSubagent],
backend: new FilesystemBackend({ rootDir: EXAMPLE_DIR }),
});
}
import { createDeepAgent, FilesystemBackend } from "deepagents";
function createContentWriter() {
const researcherSubagent = {
name: "researcher",
description:
"Research subagent with web search capability. Delegate research tasks here.",
systemPrompt:
"You are a research assistant. Use the web_search tool to find current, accurate information and return well-organized findings.",
tools: [webSearch],
};
return createDeepAgent({
model: "openrouter:z-ai/glm-5.2",
memory: ["./AGENTS.md"],
skills: ["./skills/"],
tools: [generateCover, generateSocialImage],
subagents: [researcherSubagent],
backend: new FilesystemBackend({ rootDir: EXAMPLE_DIR }),
});
}
import { createDeepAgent, FilesystemBackend } from "deepagents";
function createContentWriter() {
const researcherSubagent = {
name: "researcher",
description:
"Research subagent with web search capability. Delegate research tasks here.",
systemPrompt:
"You are a research assistant. Use the web_search tool to find current, accurate information and return well-organized findings.",
tools: [webSearch],
};
return createDeepAgent({
model: "fireworks:accounts/fireworks/models/glm-5p2",
memory: ["./AGENTS.md"],
skills: ["./skills/"],
tools: [generateCover, generateSocialImage],
subagents: [researcherSubagent],
backend: new FilesystemBackend({ rootDir: EXAMPLE_DIR }),
});
}
import { createDeepAgent, FilesystemBackend } from "deepagents";
function createContentWriter() {
const researcherSubagent = {
name: "researcher",
description:
"Research subagent with web search capability. Delegate research tasks here.",
systemPrompt:
"You are a research assistant. Use the web_search tool to find current, accurate information and return well-organized findings.",
tools: [webSearch],
};
return createDeepAgent({
model: "baseten:zai-org/GLM-5.2",
memory: ["./AGENTS.md"],
skills: ["./skills/"],
tools: [generateCover, generateSocialImage],
subagents: [researcherSubagent],
backend: new FilesystemBackend({ rootDir: EXAMPLE_DIR }),
});
}
import { createDeepAgent, FilesystemBackend } from "deepagents";
function createContentWriter() {
const researcherSubagent = {
name: "researcher",
description:
"Research subagent with web search capability. Delegate research tasks here.",
systemPrompt:
"You are a research assistant. Use the web_search tool to find current, accurate information and return well-organized findings.",
tools: [webSearch],
};
return createDeepAgent({
model: "ollama:north-mini-code-1.0",
memory: ["./AGENTS.md"],
skills: ["./skills/"],
tools: [generateCover, generateSocialImage],
subagents: [researcherSubagent],
backend: new FilesystemBackend({ rootDir: EXAMPLE_DIR }),
});
}
3
添加入口点
:::python
通过用户消息调用智能体以验证其运行状态:::::::js:::
import sys
from langchain.messages import HumanMessage
if __name__ == "__main__":
task = (
" ".join(sys.argv[1:])
if len(sys.argv) > 1
else "Write a blog post about how AI agents are transforming software development"
)
agent = create_content_writer()
result = agent.invoke(
{"messages": [HumanMessage(content=task)]},
config={"configurable": {"thread_id": "content-builder-demo"}},
)
for msg in result.get("messages", []):
if hasattr(msg, "content") and msg.content:
print(msg.content)
const task =
process.argv.slice(2).join(" ") ||
"Write a blog post about how AI agents are transforming software development";
const agent = createContentWriter();
const result = await agent.invoke({
messages: [{ role: "user", content: task }],
config: { configurable: { threadId: "content-builder-demo" } },
});
const messages = result.messages ?? [];
for (const msg of messages) {
if (msg.content) console.log(msg.content);
}
运行智能体
文件系统后端可在
root_dir下读写和删除文件。仅限专用目录运行,发布前请审阅生成内容。python content_writer.py
python content_writer.py Write a blog post about prompt engineering
npx tsx content_writer.ts
npx tsx content_writer.ts Write a blog post about prompt engineering
LANGSMITH_API_KEY配置就绪后,可通过LangSmith查看运行记录。输出
:::js 调用成功时,智能体会在项目根目录下写入生成物,例如: ::::::python 调用成功时,生成物会写入系统临时目录(macOS/Linux通常为/tmp/),而非项目文件旁。
:::blogs/
└── prompt-engineering/
├── post.md
└── hero.png
research/
└── prompt-engineering.md
SKILL.md中的技能规范。完整代码
查阅GitHub上的完整示例content-builder-agent,包含Rich框架的流式输出界面。下一步操作
- 编辑品牌规则:在
instructions.md(托管深度智能体)或AGENTS.md(SDK)中修改 - 为新内容类型添加技能至
skills/<name>/SKILL.md - SDK路径下在
subagents.yaml添加子智能体并在load_subagents注册工具;托管深度智能体则需编辑agent.py或agent.ts中的内联researcher - 阅读文档:Subagents、Skills和Customization
- 参考指南:Managed Deep Agents和从深度智能体迁移
官方原文:src/oss/deepagents/content-builder.mdx · 非官方翻译,译文由 AI 生成,以英文原文为准。