实战:用Harness做一个自动化日报Agent

摘要:DeepSeek Harness实战教程,从零搭建自动化日报Agent:用web_search并发采集热点、fetch_url_meta抓取网页、GLM-4.7-Flash生成摘要、Markdown输出到文件,零成本跑通定时任务。

前7篇咱们把Harness的零件拆了个遍:插件怎么写、模型怎么换、子代理怎么调度。今天不拆了,今天攒一个完整的东西出来。

我打算做一个自动化日报Agent :每天自动搜当天AI和编程领域的热点,抓内容,去重分类,生成一份Markdown日报存到本地。全程用GLM-4.7-Flash,不花一分钱。

跟着做,大概一个小时能跑起来。

先想清楚要干什么

动手之前别急着写代码,先把需求掰碎了。

我要的日报长这样:

  • 每天早上自动跑一次
  • 搜几个固定方向:AI大模型、开源项目、技术文章
  • 每个方向抓3-5条,去重,生成一句话摘要
  • 按固定模板拼成Markdown,文件名带日期
  • 存到本地某个目录

技术上对应到Harness的能力:

需求 Harness能力 出处
搜热点 web_search工具,rc.8支持并发 内置
抓网页内容 Day04写过的fetch_url_meta Day04
去重+分类+摘要 模型本身的能力,用Code模式批量处理 Day03
拼模板写文件 Code模式写TypeScript一次搞定 Day03
定时跑 系统cron调dsh CLI 本文

这里有个关键决策:要不要拆子代理?

Day06讲了子代理调度,理论上可以让一个Agent搜新闻、一个写摘要。但我试了之后发现,这个任务量级不大,总共就搜十几个链接,一个模型用Code模式批量处理完全够,拆子代理反而增加调度开销。所以本篇用单Agent + Code模式,简单直接。如果以后要扩展到几十个信息源,再考虑上dsh-agent-teams

整个流程画出来是这样的:
#mermaid-svg-HNr3OYI0DqHGH28f{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HNr3OYI0DqHGH28f .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HNr3OYI0DqHGH28f .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HNr3OYI0DqHGH28f .error-icon{fill:#552222;}#mermaid-svg-HNr3OYI0DqHGH28f .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HNr3OYI0DqHGH28f .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HNr3OYI0DqHGH28f .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HNr3OYI0DqHGH28f .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HNr3OYI0DqHGH28f .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HNr3OYI0DqHGH28f .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HNr3OYI0DqHGH28f .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HNr3OYI0DqHGH28f .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HNr3OYI0DqHGH28f .marker.cross{stroke:#333333;}#mermaid-svg-HNr3OYI0DqHGH28f svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HNr3OYI0DqHGH28f p{margin:0;}#mermaid-svg-HNr3OYI0DqHGH28f .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HNr3OYI0DqHGH28f .cluster-label text{fill:#333;}#mermaid-svg-HNr3OYI0DqHGH28f .cluster-label span{color:#333;}#mermaid-svg-HNr3OYI0DqHGH28f .cluster-label span p{background-color:transparent;}#mermaid-svg-HNr3OYI0DqHGH28f .label text,#mermaid-svg-HNr3OYI0DqHGH28f span{fill:#333;color:#333;}#mermaid-svg-HNr3OYI0DqHGH28f .node rect,#mermaid-svg-HNr3OYI0DqHGH28f .node circle,#mermaid-svg-HNr3OYI0DqHGH28f .node ellipse,#mermaid-svg-HNr3OYI0DqHGH28f .node polygon,#mermaid-svg-HNr3OYI0DqHGH28f .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HNr3OYI0DqHGH28f .rough-node .label text,#mermaid-svg-HNr3OYI0DqHGH28f .node .label text,#mermaid-svg-HNr3OYI0DqHGH28f .image-shape .label,#mermaid-svg-HNr3OYI0DqHGH28f .icon-shape .label{text-anchor:middle;}#mermaid-svg-HNr3OYI0DqHGH28f .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HNr3OYI0DqHGH28f .rough-node .label,#mermaid-svg-HNr3OYI0DqHGH28f .node .label,#mermaid-svg-HNr3OYI0DqHGH28f .image-shape .label,#mermaid-svg-HNr3OYI0DqHGH28f .icon-shape .label{text-align:center;}#mermaid-svg-HNr3OYI0DqHGH28f .node.clickable{cursor:pointer;}#mermaid-svg-HNr3OYI0DqHGH28f .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HNr3OYI0DqHGH28f .arrowheadPath{fill:#333333;}#mermaid-svg-HNr3OYI0DqHGH28f .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HNr3OYI0DqHGH28f .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HNr3OYI0DqHGH28f .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HNr3OYI0DqHGH28f .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HNr3OYI0DqHGH28f .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HNr3OYI0DqHGH28f .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HNr3OYI0DqHGH28f .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HNr3OYI0DqHGH28f .cluster text{fill:#333;}#mermaid-svg-HNr3OYI0DqHGH28f .cluster span{color:#333;}#mermaid-svg-HNr3OYI0DqHGH28f div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HNr3OYI0DqHGH28f .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HNr3OYI0DqHGH28f rect.text{fill:none;stroke-width:0;}#mermaid-svg-HNr3OYI0DqHGH28f .icon-shape,#mermaid-svg-HNr3OYI0DqHGH28f .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HNr3OYI0DqHGH28f .icon-shape p,#mermaid-svg-HNr3OYI0DqHGH28f .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HNr3OYI0DqHGH28f .icon-shape .label rect,#mermaid-svg-HNr3OYI0DqHGH28f .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HNr3OYI0DqHGH28f .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HNr3OYI0DqHGH28f .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HNr3OYI0DqHGH28f :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 定时触发 dsh CLI
加载 cordis.yml 配置
Agent启动
web_search 并发搜索多个关键词
URL去重 + 过滤
fetch_url_meta 批量抓取网页摘要
Code模式: 模型去重/分类/生成摘要
Code模式: 组装Markdown模板
写入本地文件 daily-report-YYYY-MM-DD.md
任务结束

项目结构

先建好目录:

bash 复制代码
mkdir -p daily-report/src
cd daily-report

最终结构:

复制代码
daily-report/
├── cordis.yml          # 插件配置
├── src/
│   ├── fetch-meta.ts   # 网页抓取插件(Day04改进版)
│   └── report-writer.ts# 文件写入插件
└── output/             # 日报输出目录

注意搜索不用自己写,Harness内置的web_searchrc.8已经支持并发查询,直接用就行。

第一步:配置模型,零成本跑起来

先确保模型配好了。Day07讲过怎么接GLM,这里快速过一下。

在全局配置里把默认模型设成GLM-4.7-Flash。这个模型免费200K上下文,跑日报这种任务绰绰有余。关键是它支持Code模式(PTC),模型可以写TypeScript把多步操作组合起来一次执行,不用一轮一轮地调工具,效率高很多。

如果你还没配,去Day07看配置步骤,五分钟搞定。配好之后可以用这个命令验证:

bash 复制代码
npx @deepseek-ai/dsh chat --model GLM-4.7-Flash "说句话"

能回复就行。

第二步:写网页抓取插件

Day04咱们写过一个fetch_url_meta,能抓网页标题和描述。但那个版本有几个问题,今天顺手改了:

  1. 只抓meta信息不够,有些网站description是空的或者乱写的
  2. 没有超时和错误处理,一个链接挂了整个任务卡住
  3. 不支持批量抓取

改进版如下,存成src/fetch-meta.ts

typescript 复制代码
import type { Context } from '@deepseek-ai/cordis'

export const name = 'fetch-meta'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register({
    name: 'fetch_url_meta',
    description: '批量抓取网页标题和正文摘要,自动处理超时和失败降级。输入URL列表,最多5个',
    parameters: {
      urls: {
        type: 'array',
        items: { type: 'string' },
        description: '要抓取的URL列表,最多5个',
      },
    },
    output: {
      schema: {
        type: 'object',
        additionalProperties: false,
        required: ['items'],
        properties: {
          items: {
            type: 'array',
            items: {
              type: 'object',
              additionalProperties: false,
              required: ['url', 'title', 'description', 'ok'],
              properties: {
                url: { type: 'string' },
                title: { type: 'string' },
                description: { type: 'string' },
                ok: { type: 'boolean' },
              },
            },
          },
        },
      },
      render: (_args, value) => [
        {
          type: 'text',
          text: value.items
            .map((item) => `${item.ok ? 'OK' : 'FAIL'} ${item.title} | ${item.description}`)
            .join('\n'),
        },
      ],
    },
    async execute({ urls }: { urls: string[] }) {
      // 限制并发,别把人家网站搞挂了
      const limited = urls.slice(0, 5)
      const results = await Promise.all(
        limited.map(async (url) => {
          try {
            // 8秒超时,不然有些网站能卡到天荒地老
            const res = await fetch(url, {
              signal: AbortSignal.timeout(8000),
              headers: {
                'User-Agent': 'Mozilla/5.0 (compatible; DailyReportBot/1.0)',
              },
            })

            const html = await res.text()

            // 提取title
            const titleMatch = html.match(/<title[^>]*>([^<]+)<\/title>/i)
            const title = titleMatch ? titleMatch[1].trim() : url

            // 提取meta description
            const descMatch = html.match(
              /<meta[^>]+name=["']description["'][^>]+content=["']([^"']+)["']/i
            )
            let description = descMatch ? descMatch[1].trim() : ''

            // description为空就从正文里抠一段
            if (!description) {
              const text = html
                .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
                .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
                .replace(/<[^>]+>/g, ' ')
                .replace(/\s+/g, ' ')
                .trim()
              description = text.slice(0, 300)
            }

            return { url, title, description: description.slice(0, 500), ok: true }
          } catch (err: any) {
            // 抓失败就返回错误信息,别抛异常,不影响其他链接
            return { url, title: url, description: `抓取失败: ${err.message}`, ok: false }
          }
        })
      )
      return { items: results }
    },
  })
}

相比Day04的版本,主要改了三个地方:

  • 批量接收URL :参数从单个url改成数组,配合Promise.all并发抓,比一个个抓快好几倍
  • 超时控制:8秒超时 + AbortSignal.timeout,不会因为一个慢网站卡死
  • 降级策略:meta description抓不到就从正文里抠前300字,实在抓不到就返回失败标记,不炸整个流程

这个降级策略很重要。我第一次跑的时候,有个链接超时了30秒,整个Agent就卡在那等。加上超时之后,最坏情况就是那条新闻没摘要,不影响其他的。

第三步:写文件输出插件

模型生成完日报内容,需要写入本地文件。这个插件很简单:

typescript 复制代码
import type { Context } from '@deepseek-ai/cordis'
import { writeFile, mkdir } from 'fs/promises'
import { join } from 'path'

export const name = 'report-writer'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register({
    name: 'write_daily_report',
    description: '将日报内容写入Markdown文件,文件名自动带日期',
    parameters: {
      content: {
        type: 'string',
        description: '日报的Markdown内容',
      },
      date: {
        type: 'string',
        description: '日期,格式YYYY-MM-DD,不传则用当天',
      },
    },
    output: {
      schema: {
        type: 'object',
        additionalProperties: false,
        required: ['success', 'filePath', 'fileName'],
        properties: {
          success: { type: 'boolean' },
          filePath: { type: 'string' },
          fileName: { type: 'string' },
        },
      },
      render: (_args, value) => [
        { type: 'text', text: `已写入 ${value.filePath}` },
      ],
    },
    async execute({ content, date }: { content: string; date?: string }) {
      const targetDate = date || new Date().toISOString().slice(0, 10)
      const outputDir = join(process.cwd(), 'output')

      await mkdir(outputDir, { recursive: true })

      const fileName = `daily-report-${targetDate}.md`
      const filePath = join(outputDir, fileName)

      await writeFile(filePath, content, 'utf-8')

      return { success: true, filePath, fileName }
    },
  })
}

存成src/report-writer.ts

有个细节:process.cwd()取的是启动dsh时的工作目录。后面我们会在daily-report目录下启动,所以文件会写到daily-report/output/下面。如果你想固定输出路径,可以把join(process.cwd(), 'output')改成绝对路径。

第四步:写cordis.yml配置

把两个插件注册进去:

yaml 复制代码
- insert:
    - id: fetch-meta
      name: 'file:///C:/path/to/daily-report/src/fetch-meta.ts'
    - id: report-writer
      name: 'file:///C:/path/to/daily-report/src/report-writer.ts'

注意要用 file:/// 形式的绝对路径 (Day04 踩过的坑:Windows 下直接写 C:\... 会被 Node 的 ESM 加载器把盘符当成协议名,报 ERR_UNSUPPORTED_ESM_URL_SCHEME)。把 /path/to/daily-report 换成你自己的项目绝对路径。

第五步:写Agent任务指令

这一步是最关键的:不是写代码,是写Prompt

Agent启动后要知道自己干什么。Harness的Code模式会让模型自己决定怎么调工具、怎么组合步骤,所以指令要把目标和约束说清楚,但不要规定每一步怎么做,那是模型的事。

在项目根目录建一个task.md

markdown 复制代码
你是一个技术日报生成助手。请按以下步骤生成今天的技术日报:

1. 使用 web_search 工具并发搜索以下关键词(一次性传入所有查询):
   - "AI大模型 最新进展"
   - "开源项目 推荐 GitHub"
   - "编程技术文章 精选"
   每个查询取前5条结果。

2. 对所有搜索结果URL去重,去掉明显不相关的链接(如首页、登录页、广告页)。

3. 使用 fetch_url_meta 工具批量抓取网页内容(每批最多5个URL)。

4. 根据抓取到的内容,整理出日报:
   - 分为三个板块:🔥 今日热点、📦 开源项目、💡 技术文章
   - 每条包含:标题(做成链接)、一句话摘要(不超过50字)
   - 去重:同一事件多个来源只保留最详细的一条
   - 每个板块3-5条,不要凑数

5. 按以下格式组装Markdown:

# 技术日报 - {日期}

## 🔥 今日热点
1. [标题](链接) - 一句话摘要
...

## 📦 开源项目
1. ...

## 💡 技术文章
1. ...

---
由 DeepSeek Harness 自动生成

6. 使用 write_daily_report 工具写入文件。

注意:
- 日期用今天的实际日期
- 摘要要具体,不要"值得关注""引发热议"这种废话
- 如果某个板块内容不够,可以少于3条,不要编
- 抓取失败的链接直接跳过,不要反复重试

写这个指令的时候我踩了几个坑,说一下:

坑一:没说"一次性传入所有查询"。 模型一开始一轮只搜一个关键词,搜完一个等结果再搜下一个,三个关键词跑了三轮。加上"一次性传入"之后,web_search的并发能力才真正用上,一轮就搜完了。

坑二:没约束摘要风格。 第一次生成的摘要全是"该项目在社区引起广泛关注""这一进展令人振奋"这种废话。加上"不要'值得关注''引发热议'这种废话"之后,输出质量明显提升。模型很听话,你得把丑话说在前面。

坑三:没说抓取失败怎么办。 有个链接超时后,模型反复重试了三次,浪费时间。加上"抓取失败的链接直接跳过,不要反复重试"就好了。

第六步:跑起来

daily-report目录下执行:

bash 复制代码
dsh web --patch ./cordis.yml

--patch加载我们的两个插件。启动后会打开浏览器界面,把task.md里的内容粘贴到输入框,发送即可。

如果想一键跑完不打开界面,用 headless 模式:

powershell 复制代码
$task = Get-Content task.md -Raw
dsh --profile headless --patch ./cordis.yml $task

第一次跑可能会有点慢,因为模型要搜、要抓、要写。正常情况下1-2分钟完成。跑完去output/目录看:

bash 复制代码
cat output/daily-report-2026-08-27.md

大概长这样:

markdown 复制代码
# 技术日报 - 2026-08-27

## 🔥 今日热点
1. [DeepSeek发布新版模型,推理能力提升40%](https://...) - 新模型在数学和代码基准上超越同级别竞品,API价格不变。
2. [某大厂开源多模态模型,支持图文混合输入](https://...) - 模型权重以MIT协议发布,可商用,参数量7B。

## 📦 开源项目
1. [xxx/xxx - 终端AI助手](https://github.com/...) - 在终端里直接调大模型,支持多模型切换和上下文管理,本周获2.3k星。
2. [xxx/xxx - SQL优化工具](https://github.com/...) - 自动分析慢查询并给出优化建议,支持MySQL和PostgreSQL。

## 💡 技术文章
1. [深入浅出RAG:从原理到生产环境](https://...) - 讲透检索增强生成的分块策略、向量选型和评估方法。
2. [TypeScript 5.4新特性详解](https://...) - 重点介绍NoInfer工具类型和模块解析改进。

---
由 DeepSeek Harness 自动生成

当然具体内容取决于当天搜出来什么。

实际运行效果:

调试过程中遇到的几个问题

问题一:搜索结果太多,筛选不准

web_search每个关键词返回10条结果,三个关键词就是30条。模型在筛选的时候有时会把不太相关的也塞进来。

解法:在指令里明确"去掉明显不相关的链接(如首页、登录页、广告页)",并且告诉模型"每个板块3-5条,不要凑数"。给了上限之后,模型自然会挑质量高的。

问题二:网页抓取乱码

有些中文网站编码不是UTF-8,抓回来一堆乱码。

解法 :在fetch_url_meta里加编码检测。不过这个问题在实际跑的时候影响不大,大多数主流技术网站都是UTF-8,个别乱码的链接模型会自动跳过。如果碰到大量乱码,可以引入chardet之类的库做编码检测,但目前没必要。

问题三:模型输出格式偶尔不稳定

大部分时候输出格式都对,但偶尔模型会在标题前面加emoji,或者把链接格式写错。

解法 :在指令里把格式模板给死,用"1. 标题 - 摘要"这种明确的格式。Code模式下模型会直接写TypeScript字符串拼接,格式遵从度比纯文本模式高很多。这也是为什么用Code模式而不是Chat模式:Code模式下模型是在"写代码生成文本",格式控制力更强。

问题四:Token消耗比预期高

第一次跑用了将近30K Token。看了一下,主要是fetch_url_meta返回的description太长,有些500字全塞进去了。

解法 :两层限制。插件层面已经截到500字了,我又在指令里加了一句"抓取到的内容如果超过200字,只取前200字用于判断"。改完之后降到15K左右,GLM-4.7-Flash的免费额度一天能跑几十次。

问题五:headless模式不支持.ts插件

dsh --profile headless一键跑的时候,报Unknown file extension ".ts"

原因:headless模式基于Node.js原生ESM加载器,没有内置TypeScript编译;只有web模式自带TS加载器,所以web模式下.ts能直接跑。

解法:日常调试用web模式就行。需要headless一键跑或定时执行时,把.ts编译成.js:

bash 复制代码
npx tsc src/*.ts --outDir dist --module esnext --target es2022

然后复制一份cordis.yml改名为cordis.js.yml,把里面的路径改成dist/fetch-meta.jsdist/report-writer.js。这样cordis.yml(.ts,web模式用)和cordis.js.yml(.js,headless用)并存,互不干扰。

问题六:web_search需要DeepSeek API key

跑的时候web_search调用失败,报no API key for "DEEPSEEK_API_KEY",然后Agent降级成基于模型知识生成示例日报(内容是对的但不是实时搜索结果)。

原因web_search底层调的是DeepSeek搜索API,需要单独的DEEPSEEK_API_KEY,跟你接大模型用的GLM key不是一回事。

解法 :去DeepSeek开放平台申请API key,然后在启动dsh前设置环境变量:

powershell 复制代码
$env:DEEPSEEK_API_KEY = "sk-xxxx"
dsh web --patch ./cordis.yml

或者在dsh web界面的模型/凭证配置页里填入。没配也能跑,Agent会自动降级,只是搜索结果变成模型基于知识生成的示例,不是当天实时热点。

第七步:定时执行

能跑起来之后,最后一步是让它每天自动跑。

macOS / Linux:cron

打开crontab:

bash 复制代码
crontab -e

加一行,每天早上8点跑:

bash 复制代码
0 8 * * * cd /path/to/daily-report && TASK=$(cat task.md) && dsh --profile headless --patch ./cordis.js.yml "$TASK" >> cron.log 2>&1

注意几个点:

  • 定时执行必须用headless模式(web模式需要人工交互,没法自动跑)
  • headless模式不支持.ts插件,所以--patch指向编译后的cordis.js.yml(里面路径是.js文件),参考问题五的编译方法
  • 任务内容用cat task.md读出来作为参数传入,不是--task(dsh没有这个参数)
  • cd到项目目录是必须的,不然相对路径找不到
  • 日志重定向到文件,出问题能排查
  • dsh的路径有时候cron找不到,可以用which dsh查出绝对路径替换

Windows:任务计划程序

Windows上用"任务计划程序"。创建一个run-daily.ps1

powershell 复制代码
Set-Location "C:\path\to\daily-report"
$task = Get-Content task.md -Raw
dsh --profile headless --patch ./cordis.js.yml $task

然后在"任务计划程序"里新建任务,触发器设每天8:00,操作选"启动程序",程序填powershell.exe,参数填-ExecutionPolicy Bypass -File "C:\path\to\run-daily.ps1"

同样,cordis.js.yml是编译后的配置(指向.js插件),因为headless模式不支持.ts。

进阶:用Harness定时器插件

如果不想依赖系统cron,社区有个dsh-cron插件(可以在Harness插件市场搜到),能在Harness内部定时触发任务。好处是配置和项目在一起,迁移方便;坏处是Harness进程得一直开着。我个人偏好系统cron,稳当。

还能怎么玩

这个日报Agent是个骨架,能扩展的地方很多:

  • dsh-memento:跨会话记忆,记住昨天报了什么,自动过滤重复新闻。不用自己维护去重数据库。
  • dsh-plan-execute :规划器用DeepSeek-R1做信息筛选策略,执行器用GLM-4.7-Flash干活,省30%-50% Token。日报这种固定任务其实不太需要,但如果要做个性化推荐(根据你的阅读历史调整内容方向),规划器就有用了。
  • dsh-agent-teams:一个Agent专门搜新闻,一个专门写摘要,一个专门校对格式。信息源多了之后值得拆。
  • dsh-mcp-connector:企查查刚开源的MCP协议连接器,内置82张能力卡片覆盖9类场景(数据查询、文件处理、企业服务等),上线两天下载就过了3000。想给日报Agent加企业工商数据查询、财经数据采集之类的能力,直接装这个就行,不用自己从头写工具插件。
  • 推送到微信/飞书:写一个发送插件,调webhook把日报推到群里。文件写入插件的逻辑改一下就行。
  • 多语言:加个翻译步骤,把英文新闻摘要翻成中文。

这些扩展不着急,先把基础版本跑稳。

小结

今天这篇没有新概念,全是前7篇东西的组合:Day04的插件写法、Day03的Code模式、Day07的GLM配置。但拼到一起能跑一个真正有用的东西,这大概就是Harness的设计哲学:给你一套好用的零件,怎么搭你说了算。

整个项目核心代码不到150行(两个插件),加上一个任务指令文件。用GLM-4.7-Flash免费跑,每天一次零成本。如果前面的文章你都跟着做了,今天这个应该是最轻松的一篇,所有零件你都见过,只是第一次把它们组装成成品。

下一篇Day09,咱们聊插件开发进阶:从Skill到自定义UI。现在咱们写的插件都是工具型的,注册一个函数让模型调。但Harness的插件能力远不止于此,你可以写自定义界面、做交互式配置面板、甚至嵌一个完整的Web应用进去。Day09带你从工具插件进阶到UI插件,让你的Agent不光能干活,还能有模有样地跟人交互。

明天见。

本文由「梅雅达编程笔记」原创,首发CSDN。

DeepSeek Harness 从零到实战系列共10篇,点个关注不迷路✨

CSDN博客:https://blog.csdn.net/2601_96428997/

相关推荐
ovO1 小时前
DeepSeek Harness 源码解读(二):沿着 ctx.llm 看懂 Cordis 与“一切皆插件”
开源·deepseek
一个处女座的程序猿1 小时前
Agent之Harness:WorkBuddy的简介、安装和使用方法、案例应用之详细攻略
agent·workbuddy·harness
AbelTomato1 小时前
博客评论系统搭建回顾
javascript·typescript·cloudflare·supabase·hyperdrive
GoCoding2 小时前
DeepSeek Harness 插件
agent·deepseek
GoCodingInMyWay2 小时前
DeepSeek Harness 插件
agent·deepseek·harness
用户0934077735142 小时前
HarmonyOS WPS Open SDK 实践:registerApp 鉴权与就绪门禁
android·typescript·harmonyos
特立独行的猫a3 小时前
仓颉语言原生 Coding Agent:cjh · 仓颉语言实现的 Harness
ai·agent·harmonyos·仓颉·cangjie·harness
穗余3 小时前
Typescript let和var区别
前端·javascript·typescript
狂师4 小时前
整理了一份 DeepSeek Harness 必备插件清单!
人工智能·开源·deepseek