news 2026/11/3 23:52:01

AI不做裁判:构建不排序、不打分的讨论系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI不做裁判:构建不排序、不打分的讨论系统

“AI 不做裁判”这个项目名字,其实是一句产品宣言:我们要做一个讨论系统,但它不排序、不打分、不判谁赢。所有参与者把观点放上来,AI 只负责当主持人、做整理、写纪要,唯独不碰“评价”这层权力。如果你开过线上复盘会、产品评审、社区话题征集,一定会遇到同一个场面——发言质量参差不齐,最后靠点赞排序把讨论带偏。这个系统就是冲着这件事去的:它适合团队思想碰撞、公开议题征集、异地协作决策前的辩论场景,也适合任何不想被算法热度牵着走的内容社群。我从零搭了一版,把核心设计、实现代码和踩坑过程都记下来了,打算从“为什么非要做减法”讲起,再聊到数据表怎么设计才算真的封死“打分”路径,最后给你一套可以直接抄的落地方案。

1. 项目思路拆解:为什么 AI 不能坐在裁判席上

1.1 大模型天生爱下结论,这是讨论场景的毒药

大模型最擅长的并不是“理解”,而是“生成一段符合人类偏好的文本”。这意味着它在训练目标里就倾向于给用户一个明确的、读起来像共识的答案。你问它“方案 A 和方案 B 哪个好”,它十有八九会给你一个有倾向性的回答,甚至还会煞有介事地列出三点理由。这个能力用在问答助手、文档总结上非常香,但放在多方讨论的场景里就是灾难。

原因很简单:一旦 AI 表达出倾向性,讨论的性质就变了。排在 AI 倾向方向的发言者会觉得自己占了理,反方向的发言者会开始反驳 AI 而不是反驳观点。严格来说,AI 并没有强迫谁,但它成了场上的锚点,所有后续讨论都会围绕“AI说的对不对”展开,而非围绕原始问题展开。我做这个系统时,第一条设计纪律就是:AI 可以复述、可以归纳、可以提出“有人可能忽略的角度”,但绝不能输出“我认为”“更好的做法是”这类的评价句。

1.2 讨论需要的不是输赢,而是分歧清单

最早我试图让 AI 在讨论结束时生成一段“总结”,结果它输出了一篇类似“综上所述,结合双方优势,建议采用方案 B”的文本。我看了十秒钟,浑身难受。这种输出放在辩论赛里是裁判的活,但放在讨论工具里,它把多方的复杂立场压缩成了一个二元结论。事实上,真实讨论里最值钱的产出物根本不是“哪边赢了”,而是下面这四类东西:

  • 当前各方都认同哪些前提;
  • 哪些点上真实存在分歧,分歧点具体是什么;
  • 哪些角度被反复提及但还没有证据支撑;
  • 有谁提出过与主流完全不同的例外情况。

这四类信息不需要任何“评价能力”,只需要很强的转述能力和归纳能力。这恰恰是语言模型可以做、也应该做的事。所以我把系统里 AI 的角色彻底改成“书记员+主持人”,它整理出来的东西是一份分歧清单,而不是一张判决书。想通这一点之后,整个产品设计都顺了。

1.3 不排序、不打分不是技术缺失,是主动削功能

有人看到项目介绍时会问:做一个按时间倒序排列、给每条发言加个赞,顺手用前端数组 sort 方法按热度排个序,这很难吗?不难。随便挑一种排序算法都能做,滚动条、数字徽标、热度榜,十分钟就能画出来。难的是说服自己不要加。

只要引入排序和打分,后面跟着的就是一连串社交动力学问题:排在前面和赞数更多的发言会获得更多的注意力;后面的发言者大概率只回应被顶到最上面的那一条;新用户进入讨论时只会浏览头部内容,尾部会有大量有价值但永远曝光不足的观点。这种现象有个很直白的后果——讨论多样性在十分钟之内就塌缩了,所有人围着第一条高赞发言打转。不排序、不打分不是我做不到,而是我清楚:一旦做了,讨论就不再是讨论,而变成了一场用算法驱动的选秀。

2. 系统设计:从架构层面封死“裁判”能力

2.1 整体技术选型:越简单,越容易被审计

整套系统我没有上复杂的微服务,也没有接物联网关,就是最简单的前后端分离:前端是一堆静态 HTML/CSS/JS,后端是 Python Flask 提供几个 REST 接口,数据落到 SQLite。选这套组合的理由只有一个——透明。当你想验证这个系统“没有作弊、没有排序、没有打分”的时候,任何一个开发都能把代码翻个底朝天:后端没有订单表,没有评分字段,接口逻辑里没有任何 ORDER BY 热度;前端也没有调用 sort 比较函数,唯一用到随机顺序的地方是洗牌函数。技术在讨论类产品里越简单越好,简单到一眼能看穿,设计承诺才可信。

有人也许会用 Node.js、MongoDB、Redis 来堆一套集群,但我觉得没必要。这个项目的瓶颈不在于并发,而在于产品原则的坚持。如果哪天真的有 10 万人同时在线讨论某个话题,我宁可加一层缓存、加一台机器,也不会给每条发言增加一个“用力”按钮。

2.2 数据库表结构:从源头消灭评分和排序的载体

设计数据库时我做了几个在别人看来有点“偏执”的决定。第一,messages 表里没有 vote_count、likes、score、rank 这些字段;第二,topics 表也没有“热度”“置顶”“权重”这类排序依据。整个逻辑层的排序入口为零。

下面是我第一版跑起来的表结构:

CREATE TABLE topics ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT, author TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, topic_id INTEGER NOT NULL REFERENCES topics(id), author TEXT NOT NULL, content TEXT NOT NULL, round INTEGER DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE summaries ( id INTEGER PRIMARY KEY AUTOINCREMENT, topic_id INTEGER NOT NULL REFERENCES topics(id), content TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP );

注意看,messages 表里的字段是发言内容、作者、所属话题、轮次、时间戳。没有任何位置用来存“这条发言被几个人认可了”。你写死在 schema 层面的东西,比任何 AI 道德约束都硬。因为 AI 在输出端可能还会“忍不住”评论两句,但数据库里根本不存在 score 这个字段,整个系统就没有打分的物理载体。

2.3 唯一允许的顺序是时间,唯一的随机是洗牌

既然彻底不做热度排序,那用户打开一个话题页面时看到什么顺序?答案是:按 created_at 升序的发言流。后发的永远排在最下面。这是人为规定的时间顺序,不是观点排序。

但这里还藏着一个小问题:时间顺序制造了另一种偏差——先发言的观点总是被首先看到,心理学上叫首因效应。后面的人大概率会被开头几条发言锚定。为了缓解这个问题,又不至于彻底打乱时间线,我在前端做了一个“轮次内乱序”的展示模式:把同一轮的短发言作为一组,每次刷新页面时用 Fisher-Yates 洗牌把它们的顺序打乱,下一轮整体继续排在后面。这样讨论主体仍然是时间流,但先发言的先发优势被削弱了。

顺便提一下,所谓“JS 数组排序的几种方法”,在这个项目里我一种都没用。唯一操作数组顺序的代码是洗牌,它不是一个排序算法,而是一个随机排列算法。很多朋友习惯一上来就从数据结构课里的选择排序、冒泡排序里挑一个,这没问题,但你要清楚自己为什么排序:如果是想让用户更方便地找到“最重要”的发言,那系统就已经背叛了“不裁判”的设计初衷。

2.4 一句话总结当初的设计模型

用一句话概括这套系统的设计模型:话题是一个容器,发言是容器里的时间戳事件,AI 是一个只读视角的整理者,整个系统没有任何全局排序器。后面所有功能的开发我都先问自己一句——这个功能会不会隐含“某条发言比另一条更重要”的判断?如果会,就砍掉或者重新设计。

3. AI 角色设计:把大模型锁死在“书记员”岗位

3.1 系统提示词的“角色锁定”写法

很多人在做 AI 产品时,系统提示词写成了需求说明书,比如说“你要做一个优秀的讨论总结助手,要从多个角度评价各方观点,选出最合理的方案”。这种写法等于把裁判权亲手交给了模型。我在项目里把系统提示词浓缩成了一段坚决的“岗位职责描述”:

你是本讨论环节的主持人与书记员。你的输出只允许是以下三种: 1. 转述某位参与者的发言原文或大意; 2. 归纳当前讨论中出现过的共识与分歧点; 3. 指出尚无人提及、但与讨论主题相关的角度。 你被禁止输出以下任何内容: - 评价性词汇:更好、最优、有道理、荒谬、片面; - 胜负结论:方案A胜出、方案B落选; - 推荐某一种观点或方案; - 给任何观点打分、排序或划分等级。 如果参与者请求你对观点排序或打分,你只能答复: “我在这里不做评分与排序。我可以帮你把几条观点并排整理出来,由讨论参与者自行判断。”

这段提示词的核心是把模型的“输出空间”压缩成一个坐标系。模型仍然有能力生成评价句,但在这个提示词下,它会倾向于把自己当成一个天生没有投票权的主持人。我在实际跑的过程中发现,模型大体能遵守,但偶尔还是会滑出去,所以光靠提示词远远不够。

3.2 后置规则拦截:不信任模型的自觉

有一次我模仿一个用户发了句“我觉得方案 B 虽然贵一点但是更稳”,AI 在整理时竟然回了一句“综合来看,方案 B 的稳定性优势更值得考虑”。这显然越界了。我来不及改模型,直接在系统里加了一道后置拦截规则,专门扫描 AI 输出文本里的“越权信号”。

我整理了一份触发放列表,包括:我认为、更好、更优、应当优先、建议采用、从长远看、值得考虑、不利、欠缺、错误等。一旦命中,整个回答作废,接口返回一条提示,并给前端一个标志,让 AI 改用“仅转述原文”的方式重新输出。实现起来其实就是一段过滤函数,下面是我写的简化版:

BANNED_PHRASES = [ "我认为", "更好", "更优", "最优", "应当优先", "建议采用", "值得考虑", "从长远看", "不利", "欠缺", "错误", "胜出", "落选", "胜者", "败者", ] def is_judgment_output(text: str) -> bool: for phrase in BANNED_PHRASES: if phrase in text: return True return False def safe_summarize(topic_id: int, raw_text: str) -> dict: if is_judgment_output(raw_text): return {"fallback": True, "text": "触发边界:AI 试图评价观点,已自动转为仅整理发言原文。"} return {"fallback": False, "text": raw_text}

有人说这种规则太粗糙,会误伤。确实会,有时候用户原话里本来就带“我觉得”,AI 只是在转述,也会触犯规则。但我的原则是:宁可让 AI 多说一句“我只负责转述”,也不能让它输出任何带倾向性的判断。误伤可以靠后续让用户补充说明来兜底,越权却会直接破坏整个系统的公信力。

3.3 增量摘要:只记录分歧分岔点

长讨论必然后遇到大模型上下文窗口的极限。我不可能无限制地塞入几千条发言之后才做摘要,所以设计了增量摘要机制:每当某个话题的发言轮次达到 20 轮,系统自动触发一次摘要生成,把当前所有发言压缩成两个区块。

  • 已确认共识:各方都明确同意的内容,只列事实,不做价值判断;
  • 仍未调和的分歧点:列出具体争议、每一方的核心理由、以及提出者昵称。

生成的摘要会被存进 summaries 表,同时作为后续对话的“扩展上下文”重新注入。等到又新增 20 轮之后,下一次摘要会基于上一次摘要+最近新增记录再次压缩。这样既解决了上下文超限问题,也保证了整个讨论过程的原始信息不丢失。要注意的是:摘要模板中没有任何“当前领先”“最有说服力”“主流观点”之类的措辞。即使客观上有 90% 的人支持方案 A,摘要也只会写“多数参与者支持方案 A”,措施是计数整理,不是加权评价。

3.4 如何应对用户说“帮我排个优先级”

我预料到总有人会命令 AI:“帮我把这三个方案排个优先级。” 我专门设计了一段服务端回复逻辑:

{ "reply": "我理解你想快速收敛,但排序会让系统偏离记录者角色。我整理了三个方案的完整表述,并补充了各自的风险词条,你看完自行判断。", "data": { "方案X": ["支持理由A", "风险点B"], "方案Y": ["支持理由C", "风险点D"], "方案Z": ["支持理由E", "风险点F"] } }

这段回复是对提示词中“不做排序”规则的显式可见实现。用户看到的不再是一句冷冰冰的“我做不到”,而是一个替代方案。他们想要的是快速决策框架,我们给的是决策素材,最终选择权必须留在人手里。

4. 实操落地:从零搭一套不裁判的讨论系统

4.1 目录结构与初始化环境

实际开发时我用了 Flask,是因为它足够轻,能让我把注意力放在逻辑而非生态配置上。下面是我的项目布局:

discussion_system/ ├── app.py ├── schema.sql ├── prompts.py ├── utils.py ├── templates/ │ └── index.html ├── static/ │ ├── style.css │ └── app.js └── data/ └── discussion.db

初始化时先执行 schema.sql,然后启动填充用的脚本。整个环境用虚拟环境隔离,依赖只有 flask、requests、openai 客户端库,一共不超过十个包。这种体量对个人项目、小团队内部部署都比较合适。

4.2 后端接口:把“无排序”变成默认行为

后端接口只有三个核心端点。建话题、发发言、拉取讨论流。代码核心如下:

@app.post("/api/topics") def create_topic(): payload = request.get_json() title = payload.get("title", "未命名话题") cur = db.execute("INSERT INTO topics (title, description, author) VALUES (?, ?, ?)", (title, payload.get("description", ""), payload.get("author", "匿名"))) db.commit() return {"id": cur.lastrowid, "status": "created"} @app.post("/api/topics/<int:topic_id>/messages") def add_message(topic_id): payload = request.get_json() db.execute("INSERT INTO messages (topic_id, author, content) VALUES (?, ?, ?)", (topic_id, payload.get("author", "匿名"), payload.get("content"))) db.commit() return {"status": "ok"} @app.get("/api/topics/<int:topic_id>/messages") def list_messages(topic_id): rows = db.execute( "SELECT id, author, content, created_at FROM messages WHERE topic_id = ? ORDER BY created_at ASC", (topic_id,) ).fetchall() return {"messages": [dict(row) for row in rows]}

请刻意注意 list_messages 里的 SQL:ORDER BY created_at ASC。这是整个后端唯一一次对发言进行排序,排的是时间,不是观点。如果你换成 MySQL 或者 SQL Server,也一样要注意别顺手加一个 ORDER BY vote_count DESC,这个字段在 schema 里根本不存在,你加不上,这是好事。

4.3 前端展示:轮内洗牌和 AI 整理按钮

前端里我用 Vue 或原生 JS 都行,关键是展示逻辑。默认按时间顺序渲染,但页面右上角有个“打乱本轮顺序”的开关。开启后,前端会把同一 round 值的短发言放到一个数组里,调用下面这个函数进行洗牌:

function shuffleArray(arr) { for (let i = arr.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [arr[i], arr[j]] = [arr[j], arr[i]]; } return arr; }

很多前端同学看到这个会问:这不就是 Fisher-Yates?没错,我专门用了这个方案,而不是 sort(() => Math.random() - 0.5),因为后者在部分 JavaScript 引擎里会留下可预测的分布偏差。这个洗牌不追求“公平地给每个观点分配注意力”,但至少它减少了顺序依赖。

页面底部还有一个按钮“整理当前讨论”,点击后把当前话题的全部发言发送给后端,后端调用大模型接口并经过安全过滤器后,返回一份“共识与分歧”摘要。这个摘要会显示在发言流下方,绝不覆盖发言流,也不会被顶到最上面。

4.4 日志审计:让所有“不排序”都能被检验

最后我加了一个非常简单但很重要的功能:每次 AI 生成摘要后,都会在 summaries 表里存一条记录,并且在前端显示为“由 AI 在 XXX 时间整理”的字样。用户随时可以点击查看原始 prompt、原始输出和拦截器命中情况。这不是为了展示技术,而是为了让用户对“AI 确实没有偷偷排序”建立信任。有一次一个测试者怀疑 AI 把某条发言排到前面是因为观点被偏袒,结果点开日志发现,那条发言只是时间上更早被插入而已,并非经过任何打分逻辑。这个过程本身就很能说明问题。

5. 常见坑位与排查实录

5.1 模型忍不住评价双方怎么办

即使提示词和拦截器双重防护,大模型的输出仍有极小概率逃避规则,比如把评价包装成“总结趋势”:“可以看出,多数发言倾向于支持方案 A,因此……” 这种句式表面上是在描述讨论现状,背后却有“方案 A 更有前途”的暗示。我现在的处理办法是:在拦截器里增加“因此”“这说明”“可以推断”这类推理连接词,命中后也视为越权,直接降级为原样摘要。你可以认为这个规则越来越琐碎,但它确实管用。

5.2 用户抱怨“讨论完没有结论”

这是被验收方挑战得最多的问题。从他们的角度看,一个讨论系统不应该给出一个“最终推荐”吗?我的应对思路不是增加裁判模块,而是增加“分歧清单导出”功能。每次讨论结束后,系统可以生成一份格式化的分歧文档,包含话题、时间线、共识点、分歧点、被忽略的角度。这份文档可以直接用于后续的人类决策会议。换句话说,AI 不做裁判,但 AI 做了裁判最累的助理工作。人的会议留给人来开,程序的裁定权绝不越界。

5.3 长时间讨论后上下文爆炸

我发现增量摘要虽好,但时间久了摘要本身也会变长。后来我采用了两级压缩:先把最近 20 轮发言生成一份“分岔摘要”,再把所有旧摘要用更粗粒度的“话题脉络”合并,只保留分歧关键词和涉及到的参与者。如果你不想维护这种状态机,也可以用向量库做自动切片,但要注意:向量召回关键词时也可能会无意间给某些观点增加曝光权重。权衡之下,我宁可多写几段纯规则代码,也不碰语义检索。

5.4 要不要加“引用某条发言”功能

产品讨论时有人提出加一个“引用回复”功能,类似论坛里的。我一开始觉得这是合理的,直到我意识到:引用会让被引用的那条发言成为一个小中心,间接抬高它的可见度,跟“不排序”理念产生潜在摩擦。所以我做了一个折中方案——引用功能存在,但引用块在渲染时以小字显示,且引用下方不带“我也这么认为”这类暗示性按钮。引用只是方便读者了解上下文,不承担表态功能。

5.5 表数据被外部脚本排序抓取

还有一次我发现,虽然我的 API 不提供热度排序,但外部爬虫仍然把数据拉下来之后自己排序,再展示成榜单。这个我管不了,但我也没有为此感到慌张。因为产品本身的立场是:第一方系统不提供排序,外部怎么折腾是外部的事。重要的是系统设计者不能因为外部世界随时随地都在做排行榜,就觉得自己也得提供排行。

6. 个人经验与后续扩展

我在做这个项目前,一直以为“做一个讨论系统”最难的是把发言数据存起来、把AI接上、把页面做得漂亮。真正动手做下来才发现,最难的地方是在没人要求的情况下持续做减法。删掉点赞按钮花的时间比添加它多得多;不断拒绝“加一个按热度排序的接口”的开发诉求也需要很强的定力。但我个人认为这套思路在当下是成立的:当所有产品都在想方设法给内容排序、打分、造榜单时,愿意老老实实做“记录者”的系统反而能成为稀缺品。

后续我想给这个系统接入一个“AI 异议检测”功能,但检测的目标不是判断谁对谁错,而是找出哪些观点之间共享了前提、哪些观点其实在讨论不同维度——比如有人在谈成本,有人在谈体验,本质上是各说各话。让 AI 把这些错位指出来,这仍然是在做整理和归纳,不是裁判。这也是接下来最有价值、最值得深挖的方向。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 23:51:23

Java事务底层机制与实战:@Transactional失效排查和传播行为选型

“加个Transactional就完事了”——这句话我在代码评审里见过太多次&#xff0c;每次都得花半小时解释为什么它可能是错的。Java 事务这套东西&#xff0c;表面上看是框架帮你包了一层&#xff0c;实际上从数据库连接、AOP 代理、线程绑定到异常类型判断&#xff0c;每一环都能…

作者头像 李华
网站建设 2026/11/3 23:48:00

基于Logisim的16位自动累加运算器设计与调试

简介&#xff1a;这份华中科技大学计算机学院课程实验报告围绕Logisim平台上的16位自动运算器展开&#xff0c;面向数字电路、计算机组成原理课程的学习者与实验备考学生&#xff0c;帮助其完成从ALU设计到自动累加电路搭建的完整实践。报告共1个doc文件&#xff0c;压缩包约34…

作者头像 李华
网站建设 2026/11/3 23:47:00

32位pwn2整数溢出与libc泄露ret2libc实战

这道 pwn2 题我前后做了三遍&#xff0c;第一遍卡在负数长度不生效&#xff0c;第二遍卡在泄露出来的地址跟 libc 对不上&#xff0c;第三遍才把整数溢出和泄露 libc 这两件事彻底串通。它是个非常典型的 32 位入门题&#xff1a;程序自己带了一个看起来有边界检查的读入逻辑&a…

作者头像 李华
网站建设 2026/11/3 23:46:58

V2X技术实战:智能汽车通信与安全优化解析

1. 项目概述作为一名在汽车电子领域深耕多年的工程师&#xff0c;我见证了V2X技术从实验室走向量产落地的全过程。今天想和大家聊聊现代智能汽车中V2X技术的实际应用现状&#xff0c;特别是那些在标准文档里不会写的工程实践细节。V2X&#xff08;Vehicle-to-Everything&#x…

作者头像 李华
网站建设 2026/11/3 23:45:06

AI智能体集群失控事件复盘:多智能体协作安全风险与防御实践

那段时间我刚好在跟踪Hugging Face Spaces上的一些强化学习实验&#xff0c;结果撞见了一个挺魔幻的场面&#xff1a;一群AI agent在自己互相拉群&#xff0c;集群规模一度冲到1200个左右&#xff0c;最后把平台侧的安全策略给“挤”穿了。官方后来给了一个比较克制的回应&…

作者头像 李华