im_wower
·
2026-03-31
runtime.py
1"""
2CIE Runtime — 统一接口(SPEC §5)
3
4六个方法:ingest, step, emit, commit_feedback, snapshot_state, reset_session
5这是 Branch B 的工程稳健 runtime 实现。
6"""
7
8import random
9import math
10from typing import Optional
11from .graph import Graph
12from .state import CIEState
13from .dynamics import Dynamics
14
15
16class CIERuntime:
17 """
18 CIE 运行时——图原生认知推理引擎。
19
20 Branch B 定位:工程稳健增强 runtime。
21 先能跑、先能验证、先能出结果。
22 """
23
24 def __init__(self, seed: int = None):
25 self.graph = Graph()
26 self.state = CIEState()
27 self.dynamics = Dynamics(self.graph, self.state)
28 self.rng = random.Random(seed)
29
30 # ── 输出缓冲 ──
31 self._output_buffer: list[dict] = []
32 self._last_output: Optional[dict] = None
33
34 # ── 回灌标记 ──
35 self._feedback_pending = False
36
37 # ──────────────────────────────────────
38 # §5.1 ingest — 接收输入,注入图中
39 # ──────────────────────────────────────
40
41 def ingest(self, input_data, context=None, anchors=None):
42 """
43 接收新的输入、上下文、可选锚点提示,注入图中。
44
45 input_data: str 或 list[str]
46 - str: 文本,按字符拆分为 bigram 注入
47 - list[str]: 已分好的 token 列表
48 context: dict, optional
49 - 额外上下文信息
50 anchors: list[str], optional
51 - 锚点提示——谁、在哪、做什么
52
53 输出即输入:如果有上一轮输出,自动回灌。
54 """
55 # ── 输出即输入回灌 ──
56 if self._last_output is not None and self._feedback_pending:
57 self._feedback_loop(self._last_output)
58 self._feedback_pending = False
59
60 # ── 解析输入为 token 序列 ──
61 if isinstance(input_data, str):
62 tokens = list(input_data)
63 elif isinstance(input_data, (list, tuple)):
64 tokens = list(input_data)
65 else:
66 tokens = [str(input_data)]
67
68 if not tokens:
69 return
70
71 # ── 并行归位:所有 token 同时注入图 ──
72 # "一把种子同时撒在图的不同层级上"
73 for token in tokens:
74 if not self.graph.has_node(token):
75 self.graph.add_node(token, label=token)
76 self.state.init_node(token, phi_val=self.rng.gauss(0.0, 0.1))
77
78 # 注入激活
79 inject_amount = 100.0 / max(len(tokens), 1) * 0.5 # 半杯水
80 self.state.activate(token, inject_amount)
81
82 # ── 建立 bigram 边(非对称) ──
83 for i in range(len(tokens) - 1):
84 src, dst = tokens[i], tokens[i + 1]
85 existing_w = self.graph.get_edge_weight(src, dst)
86 # 正向强化,反向弱化——产生非对称
87 asym = self.rng.gauss(0.0, 0.1)
88 self.graph.add_edge(
89 src, dst,
90 weight=existing_w + 1.0 / (1.0 + existing_w * 0.1) + abs(asym),
91 bwd_weight=existing_w + 1.0 / (1.0 + existing_w * 0.1) - abs(asym) * 0.5,
92 edge_type='bigram'
93 )
94
95 # ── 锚点注入 ──
96 if anchors:
97 for anchor in anchors:
98 if not self.graph.has_node(anchor):
99 self.graph.add_node(anchor, label=anchor)
100 self.state.init_node(anchor, phi_val=1.0)
101 # 锚点高置信度
102 self.state.update_confidence(anchor, 2, amount=10.0) # 锚点/独立引用
103 # 锚点高势场
104 self.state.phi[anchor] = self.state.phi.get(anchor, 0.0) + 1.0
105
106 # ── 标记有输出需要回灌 ──
107 self._feedback_pending = True
108
109 # ──────────────────────────────────────
110 # §5.2 step — 推进动力学演化
111 # ──────────────────────────────────────
112
113 def step(self, n: int = 1):
114 """
115 推进 n 步内部动力学演化。
116 必须真实改变内部状态。
117 """
118 for _ in range(n):
119 self.dynamics.step()
120
121 # ──────────────────────────────────────
122 # §5.3 emit — 生成输出
123 # ──────────────────────────────────────
124
125 def emit(self) -> dict:
126 """
127 生成当前输出。允许完整输出或降级输出。
128
129 输出基于当前激活区域的行动释放值排序。
130 半杯水也要能流,不等满了再倒。
131 """
132 self.state.update_output_mode()
133
134 # 计算每个活跃节点的行动释放
135 releases = {}
136 for node_id in self.state.active_region:
137 u = self.dynamics.action_release(node_id)
138 if u > 1e-10:
139 releases[node_id] = u
140
141 # 按释放值排序
142 sorted_nodes = sorted(releases.items(), key=lambda x: -x[1])
143
144 # 根据输出模式决定输出多少
145 mode = self.state.output_mode
146 if mode == 'full':
147 top_nodes = sorted_nodes[:10]
148 elif mode == 'degraded':
149 top_nodes = sorted_nodes[:3]
150 else: # minimal
151 top_nodes = sorted_nodes[:1]
152
153 output = {
154 'mode': mode,
155 'activated': [
156 {
157 'node': nid,
158 'label': self.graph.get_node(nid).label if self.graph.get_node(nid) else nid,
159 'release': u,
160 'phi': self.state.phi.get(nid, 0.0),
161 'mu': self.state.mu.get(nid, 0.0),
162 'confidence': self.state.get_confidence(nid),
163 }
164 for nid, u in top_nodes
165 ],
166 'step': self.state.step_count,
167 'attention_free': self.state.attention.free,
168 'active_count': len(self.state.active_region),
169 }
170
171 self._last_output = output
172 self._output_buffer.append(output)
173 return output
174
175 # ──────────────────────────────────────
176 # §5.4 commit_feedback — 反馈写回
177 # ──────────────────────────────────────
178
179 def commit_feedback(self, feedback: dict):
180 """
181 把反馈写回系统——经验沉积、技能带修正、能力核慢更新。
182
183 feedback: dict
184 - 'correct': list[str] — 正确的节点,增强置信度
185 - 'wrong': list[str] — 错误的节点,降低置信度
186 - 'reward': float — 全局奖励信号
187 """
188 effect = {'reinforced': [], 'weakened': [], 'reward': 0.0}
189
190 # 正确的节点:增强置信度(cat2=独立引用) + 势场
191 for node_id in feedback.get('correct', []):
192 if self.graph.has_node(node_id):
193 self.state.update_confidence(node_id, 2, amount=2.0)
194 self.state.phi[node_id] = (
195 self.state.phi.get(node_id, 0.0) + 0.5
196 )
197 effect['reinforced'].append(node_id)
198
199 # 错误的节点:衰减势场 + 削弱置信度
200 for node_id in feedback.get('wrong', []):
201 if self.graph.has_node(node_id):
202 self.state.phi[node_id] = (
203 self.state.phi.get(node_id, 0.0) * 0.5
204 )
205 self.state.weaken_confidence(node_id, amount=3.0)
206 effect['weakened'].append(node_id)
207
208 # 全局奖励
209 reward = feedback.get('reward', 0.0)
210 effect['reward'] = reward
211 if reward > 0:
212 # 正奖励强化当前激活区域——按已有最强分量方向增强
213 for node_id in self.state.active_region:
214 if node_id in self.state.confidence:
215 alphas = self.state.confidence[node_id]
216 best_cat = alphas.index(max(alphas))
217 self.state.update_confidence(node_id, best_cat, amount=reward)
218 else:
219 self.state.update_confidence(node_id, 0, amount=reward)
220 elif reward < 0:
221 # 负奖励衰减当前激活区域(势场+置信度)
222 for node_id in self.state.active_region:
223 self.state.phi[node_id] *= max(0.1, 1.0 + reward)
224 self.state.weaken_confidence(node_id, amount=abs(reward))
225
226 self.state.last_feedback_effect = effect
227
228 # ──────────────────────────────────────
229 # §5.5 snapshot_state — 导出摘要
230 # ──────────────────────────────────────
231
232 def snapshot_state(self) -> dict:
233 """导出可比较的运行时摘要(SPEC §6)。"""
234 state_snap = self.state.snapshot()
235 state_snap['graph'] = {
236 'node_count': self.graph.node_count,
237 'edge_count': self.graph.edge_count,
238 }
239 return state_snap
240
241 # ──────────────────────────────────────
242 # §5.6 reset_session — 清理会话态
243 # ──────────────────────────────────────
244
245 def reset_session(self):
246 """
247 清理当前会话态,但不破坏长期结构层数据。
248 保留:φ(地形)、ability_cores、anchor_nodes
249 清理:μ(激活)、active_region、attention、output_buffer
250 """
251 # 清理激活
252 for node_id in list(self.state.active_region):
253 self.state.deactivate(node_id)
254 self.state.mu = {k: 0.0 for k in self.state.mu}
255 self.state.active_region.clear()
256 self.state.attention = type(self.state.attention)(total=100.0)
257
258 # 清理边流
259 self.state.J.clear()
260
261 # 清理输出缓冲
262 self._output_buffer.clear()
263 self._last_output = None
264 self._feedback_pending = False
265
266 # 保留:phi, confidence, anchor_nodes, ability_cores,
267 # experience_hits, experience_regions, skill_belt_candidates
268
269 self.state.output_mode = 'minimal'
270
271 # ──────────────────────────────────────
272 # 内部:输出即输入回灌
273 # ──────────────────────────────────────
274
275 def _feedback_loop(self, last_output: dict):
276 """
277 输出即输入——上一轮的激活结果直接成为下一轮输入的一部分。
278 不经过外部中转,闭合自指环路。
279 """
280 if not last_output or not last_output.get('activated'):
281 return
282
283 # 把上一轮输出的节点作为弱输入回灌
284 # 用 mu(激活量)而非 release(行动释放)——mu 是水量,release 是水压
285 for item in last_output['activated']:
286 node_id = item['node']
287 if self.graph.has_node(node_id):
288 mu_val = item.get('mu', 0.0)
289 # 回灌量 = 上轮激活的 5%(衰减版)
290 feedback_amount = mu_val * 0.05
291 if feedback_amount > 0.001:
292 self.state.activate(node_id, feedback_amount)
293 # 极微增强 φ(水流过的地方地形被改变)
294 self.state.phi[node_id] = (
295 self.state.phi.get(node_id, 0.0) + feedback_amount * 0.01
296 )
297
298
299 # ──────────────────────────────────────
300 # 便利方法
301 # ──────────────────────────────────────
302
303 def run(self, input_data, steps: int = 5, context=None, anchors=None) -> dict:
304 """便利方法:ingest + step + emit 一条龙"""
305 self.ingest(input_data, context=context, anchors=anchors)
306 self.step(n=steps)
307 return self.emit()