实战:用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_search在rc.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.js和dist/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/

相关推荐
用户09340777351413 小时前
HarmonyOS WPS Open SDK 工程实践:把 registerApp 做成就绪门禁
typescript·harmonyos
大模型真好玩13 小时前
DeepSeek Harness 插件的服务与事件监听详解
人工智能·agent·deepseek
东哥168814 小时前
试了10个AI助手后,我发现只有这个能让我"睡后工作
deepseek
Hello.Reader14 小时前
tsrs 技术解析用 Rust 移植 TypeScript 7,类型检查还能怎样提速?
开发语言·rust·typescript
正在走向自律19 小时前
Linux 服务器部署 DeepSeek 大模型完全指南(2026 版)
linux·运维·服务器·deepseek·部署deepseek·安装ollama·配置api服务
我才是银古20 小时前
把 666 个会话摊开看:一份 DSH 使用经验与教训的复盘
ai·deepseek·dsh
猿究院--Cu-Sn合金21 小时前
Spring Boot + DeepSeek 求职 Agent 实践:工具注册、多轮调用与简历 JD 对比
数据库·人工智能·spring boot·后端·deepseek
论文复现现场21 小时前
DeepSeek V4.1 Flash 和 V4 Pro 有什么区别?API 价格、性能与迁移建议
java·服务器·人工智能·python·大模型api·deepseek·deepseek v4.1
承渊政道21 小时前
飞牛NAS部署Hermes AI Agent:接入DeepSeek、微信与公网访问完整教程
人工智能·微信·nas·deepseek·hermes
一拳不是超人1 天前
用了两周,我给 DeepSeek Harness 写了 5 个插件
人工智能·ai编程·deepseek