my prefect server setup prefect-metrics.waow.tech
python orchestration
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

reframe relationship discovery as thematic clustering

instead of asking the LLM to evaluate pairs (which sonnet found zero of),
ask it to identify thematic clusters of tags, then derive pairwise edges
from cluster membership. this matches how the tags actually relate — they
form thematic groups, not isolated pairs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+55 -21
+44 -21
flows/weave.py
··· 24 24 from prefect.context import TaskRunContext 25 25 from prefect.variables import Variable 26 26 27 - from mps.phi import TagMerge, TagRelationship 27 + from mps.phi import TagCluster, TagMerge, TagRelationship 28 28 29 29 PHI_DID = "did:plc:65sucjiel52gefhcdcypynsr" 30 30 TAG_REL_NAMESPACE = "phi-tag-relationships" ··· 336 336 # --------------------------------------------------------------------------- 337 337 338 338 339 - class RelationshipProposal(BaseModel): 340 - relationships: list[TagRelationship] = Field(default_factory=list) 339 + class ClusterProposal(BaseModel): 340 + clusters: list[TagCluster] = Field(default_factory=list) 341 341 342 342 343 343 @task( ··· 356 356 api_key: str, 357 357 model_name: str = "claude-sonnet-4-6", 358 358 ) -> list[dict[str, Any]]: 359 - """Give the LLM the full tag list with co-occurrence context to find relationships.""" 359 + """Ask the LLM to identify thematic clusters, then derive pairwise edges.""" 360 360 tags = [t for t in sorted(tag_info.keys()) if t not in merged_aliases] 361 361 362 - # precompute co-occurrence hints to give the LLM as context 362 + # precompute co-occurrence hints 363 363 cooccur_hints: dict[str, list[str]] = defaultdict(list) 364 364 for pair_key, count in cooccurrences.items(): 365 365 t1, t2 = pair_key.split("|", 1) ··· 393 393 agent = Agent( 394 394 model, 395 395 system_prompt=( 396 - "you are mapping relationships between tags in phi's memory graph.\n" 396 + "you are organizing phi's memory tags into thematic clusters.\n" 397 397 "phi is a bluesky bot that remembers conversations and builds knowledge.\n\n" 398 398 "you will receive the full tag inventory with usage counts, sample observations, " 399 - "and co-occurrence data. your job: identify genuine conceptual relationships.\n\n" 400 - "relationship types:\n" 401 - "- RELATED: broadly connected concepts\n" 402 - "- SUBTOPIC: one is a narrower form of the other\n" 403 - "- OVERLAPPING: partially shared meaning but distinct\n\n" 399 + "and co-occurrence data. your job: identify thematic clusters — groups of tags " 400 + "that belong to the same area of phi's knowledge or experience.\n\n" 401 + "examples of good clusters:\n" 402 + "- 'phi's epistemic concerns': epistemology, memory, confabulation, self-attestation\n" 403 + "- 'technical interests': programming, ai-systems, infrastructure\n" 404 + "- 'social dynamics': community, trust, collaboration\n\n" 404 405 "rules:\n" 405 - "- assign confidence 0.0-1.0 based on how strong the connection is\n" 406 - "- co-occurrence is a signal but not proof — two tags appearing together " 407 - "might be coincidental\n" 408 - "- look for thematic clusters, not just pairs\n" 409 - "- provide brief evidence for each relationship\n" 410 - "- be selective — only include relationships you're genuinely confident about\n" 411 - "- skip trivially obvious connections (like a tag co-occurring with itself)" 406 + "- a tag can appear in multiple clusters (topics overlap)\n" 407 + "- clusters should have 2-8 tags — small enough to be coherent\n" 408 + "- assign cohesion 0.0-1.0: how tightly the tags relate to the cluster theme\n" 409 + "- name each cluster concisely (2-4 words)\n" 410 + "- describe what ties the tags together\n" 411 + "- not every tag needs a cluster — singletons with no thematic neighbors are fine to skip\n" 412 + "- use the sample observations and co-occurrence data to inform your groupings" 412 413 ), 413 - output_type=RelationshipProposal, 414 - name="tag-relator", 414 + output_type=ClusterProposal, 415 + name="tag-clusterer", 415 416 ) 416 417 417 418 result = await agent.run( 418 419 f"full tag inventory ({len(tags)} tags after merges):\n{inventory}" 419 420 ) 420 - return [r.model_dump() for r in result.output.relationships] 421 + 422 + # derive pairwise relationships from cluster membership 423 + relationships: list[dict[str, Any]] = [] 424 + seen_pairs: set[tuple[str, str]] = set() 425 + for cluster in result.output.clusters: 426 + members = [t for t in cluster.tags if t in set(tags)] 427 + for i, t1 in enumerate(members): 428 + for t2 in members[i + 1 :]: 429 + pair = tuple(sorted([t1, t2])) 430 + if pair in seen_pairs: 431 + continue 432 + seen_pairs.add(pair) 433 + relationships.append( 434 + TagRelationship( 435 + tag_a=pair[0], 436 + tag_b=pair[1], 437 + relationship_type="related", 438 + confidence=cluster.cohesion, 439 + evidence=f"[{cluster.name}] {cluster.description}", 440 + ).model_dump() 441 + ) 442 + 443 + return relationships 421 444 422 445 423 446 # ---------------------------------------------------------------------------
+11
packages/mps/src/mps/phi.py
··· 26 26 ) 27 27 28 28 29 + class TagCluster(BaseModel): 30 + """A thematic grouping of related tags.""" 31 + 32 + name: str = Field(description="short name for the cluster theme") 33 + description: str = Field(description="what ties these tags together") 34 + tags: list[str] = Field(description="member tags") 35 + cohesion: float = Field( 36 + ge=0.0, le=1.0, description="how tightly related are these tags" 37 + ) 38 + 39 + 29 40 class TagRelationship(BaseModel): 30 41 """A discovered relationship between two distinct tags.""" 31 42