LabHub
学习 学习路径 课程

AI 智能体 — 是图不是模型

把上限调高,那一单还是跑不完

在 LabHub 中继续学习

한국어 원문으로 표시합니다.

목표

고리가 있는 그래프를 직접 만들고, 재귀 한도가 무엇을 세는지 자기 손으로 재고, 상한에 닿은 것과 할 일을 마친 것을 다른 결과로 남긴다. 마지막으로 끝내는 조건에 닿지 못하는 입력을 가려내는 진단을 만든다.

왜 중요한가

LangGraph 에서 고리는 특별한 문법이 아니라 그냥 뒤로 가는 엣지다. 그래서 만들기 쉽고, 끝내는 것이 어렵다. 끝내는 조건이 있어도 그 조건에 닿을 수 없는 입력이 하나 섞이면 그 건은 영원히 돈다 — 이 실습의 에이전트가 딱 그렇다. 점수를 깎는 이유가 둘(금칙어·길이)인데 고치는 노드는 하나만 고친다. 재귀 한도는 이럴 때 마지막 방어선이지만, 그것이 세는 단위를 모르면 진단을 잘못한다. 한도가 세는 것은 노드 실행 횟수가 아니라 수퍼스텝이고, 나란히 둔 노드는 몇 개든 한 수퍼스텝이다. 이 실습에서 직접 재어 확인합니다. 그리고 한도에 닿아 예외가 난 것과 그래프가 스스로 끝낸 것은 완전히 다른 사건이다. 같은 칸에 "실패" 로 적어 두면 나중에 무엇이 문제였는지 가를 수 없다. 상한을 두 겹(상태의 roundsrecursion_limit)으로 두고, 안쪽 상한은 결과를 남기게 만든다. 채점기는 여러분이 적어 둔 설명을 믿지 않는다. 여러분의 모듈을 실제로 불러 규칙 함수를 임의의 문장으로 두드려 보고, 그래프를 임의의 한도로 돌려 나온 결과를 채점기가 따로 계산한 값과 대조한다.

단계

  1. /root/work/agroute/route.pyBANNED·MIN_LEN·PASS·make_draft·score_of·revise_text·State·노드 넷(compose·review·revise·shipafter_review·build_graph() 를 만드세요. review 에서 갈리는 조건부 엣지에는 경로 지도를 주고, 이 단계에서는 revise 다음이 END 입니다.
  2. revise 에서 review 로 돌아오는 엣지를 더해 고리를 만드세요. 금칙어가 여러 개인 문의가 여러 바퀴를 돌아 통과해야 합니다.
  3. build_unbounded()run_unbounded(question, limit) 를 더하세요. 끝내는 조건을 일부러 뺀 판을 주어진 한도로 돌리고, 한도에 닿으면 {"error": "GraphRecursionError", "limit": 한도, "message": 예외 메시지} 를 돌려줍니다.
  4. MAX_ROUNDS = 5escalate 노드를 더해 build_graph() 가 어떤 입력에도 예외 없이 끝나게 하세요. 상한에 닿으면 outcomeescalate 입니다.
  5. chain_graph(n)·fan_graph(n)·min_limit(app, state) 를 더하세요. min_limit 은 그 그래프를 끝까지 돌리는 데 필요한 가장 작은 recursion_limit 을 찾습니다.
  6. run_guarded(question, limit) 를 더해 마친 것과 상한에 닿은 것을 다른 status 로 남기세요.
  7. diagnose(question) 을 더해 이 입력이 규칙을 만족할 수 있는지, 없다면 왜인지(too_short 또는 banned) 가려내게 하세요.
  8. /root/work/agroute/route_report.json/root/work/agroute/route_report.md 에 재어 본 숫자와 판단을 기록하세요.

참고

갈래 이름과 경로 지도를 나눈다

/root/work/agroute/route.py 에 규칙 함수 셋과 노드 넷, after_review, build_graph() 를 만드세요. review 의 조건부 엣지에는 경로 지도 {"ship": "ship", "revise": "revise"} 를 주고, 이 단계에서는 revise 다음이 END 입니다.

조건 함수는 상태를 받아 갈래 이름을 돌려줍니다. 노드 이름을 직접 돌려주게 만들면 그래프 모양을 바꿀 때마다 판단 코드를 고쳐야 합니다. score_of 가 어떻게 점수를 깎는지가 뒤 단계의 재료이니 지시문의 규칙을 정확히 지키세요.

고친 것을 다시 재러 보낸다

revise 에서 review 로 돌아오는 엣지를 더해 고리를 만드세요. 금칙어가 셋인 문의는 세 바퀴를 돌아 ship 으로 가야 합니다.

고리는 특별한 문법이 아니라 그냥 뒤로 가는 엣지입니다. revise 가 금칙어를 한 번에 하나만 지운다는 점이 바퀴 수를 정합니다. 바퀴 수를 세는 roundsrevise 가 올립니다 — 그래야 나중에 안쪽 상한을 걸 자리가 생깁니다.

한도에 닿는 것을 직접 본다

build_unbounded()run_unbounded(question, limit) 를 더하세요. 끝내는 조건을 일부러 뺀 판을 주어진 한도로 돌리고, 한도에 닿으면 {"error": "GraphRecursionError", "limit": 한도, "message": 예외 메시지} 를, 끝났으면 error 를 빈 문자열로 돌려줍니다.

예외는 langgraph.errors.GraphRecursionError 입니다. 메시지에 한도 숫자가 그대로 들어 있으니 지어내지 말고 str(예외) 를 그대로 담으세요. build_unbounded()build_graph()다른 그래프여야 합니다 — 뒤 단계에서 build_graph() 에 상한을 넣어도 이 단계가 계속 유효해야 하기 때문입니다.

결과를 남기는 안쪽 상한

MAX_ROUNDS = 5escalate 노드를 더하고 after_review 가 상한에서 escalate 갈래를 돌려주게 하세요. 경로 지도에도 그 갈래를 더합니다. 이제 build_graph() 는 어떤 입력에도 예외 없이 끝나야 합니다.

바깥 상한(recursion_limit)에 닿으면 예외라 결과가 사라집니다. 안쪽 상한은 결과를 남깁니다 — 그것이 이 단계의 요점입니다. 판단은 after_review 한 곳에만 두세요. 노드 안에서도 끝낼지 보면 두 곳이 어긋나는 날이 옵니다.

한도가 세는 것은 수퍼스텝이다

chain_graph(n)(줄줄이)·fan_graph(n)(나란히)·min_limit(app, state) 를 더하세요. min_limit 은 그 그래프를 끝까지 돌리는 데 필요한 가장 작은 recursion_limit 을 찾아 돌려줍니다.

1 부터 올려 가며 invoke 를 해 보고 처음 성공하는 값을 돌려주면 됩니다. 두 그래프의 답이 어떻게 다른지가 이 단계의 핵심입니다 — 나란히 둔 노드는 몇 개든 같은 수퍼스텝에서 돕니다. 상태는 리듀서가 붙은 열쇠 하나면 충분합니다.

마친 것과 닿은 것을 가른다

run_guarded(question, limit=25) 를 더하세요. 그래프가 스스로 끝났으면 {"status": "done", "rounds": 정수, "outcome": "ship"|"escalate", "score": 정수}, 한도에 닿았으면 {"status": "limit", "rounds": -1, "outcome": "", "score": -1} 입니다.

두 사건을 같은 칸에 "실패" 로 적으면 나중에 가를 수 없습니다. 예외를 잡아 다른 이름을 붙이는 것이 전부이지만, 그 한 줄이 운영에서 크게 갈립니다. 한도를 작게 주면 정상 입력도 limit 이 나옵니다 — 채점기가 그것을 확인합니다.

고쳐도 나아지지 않는 입력을 가려낸다

diagnose(question) 을 더해 {"fixable": 참거짓, "reason": ""|"too_short"|"banned", "best_score": 정수, "rounds_needed": 정수} 를 돌려주게 하세요. best_score 는 금칙어를 더 지울 수 없을 때까지 지운 뒤의 점수입니다.

그래프를 돌리지 않고도 알 수 있습니다 — revise_text 를 더 바뀌지 않을 때까지 적용해 보고 그때의 점수를 재면 됩니다. 그 점수가 PASS 에 못 미치면 이 입력은 아무리 돌려도 통과하지 못합니다. 진단이 한도를 올리는 것보다 값싼 이유가 여기 있습니다.

재어 본 숫자로 보고한다

/root/work/agroute/route_report.jsondefault_recursion_limit·chain_min_limit·fan_min_limit·clean·dirty·stuck·stuck_reason 을, /root/work/agroute/route_report.md## 고리를 어디에 두었나 ## 재귀 한도는 무엇을 세는가 ## 상한에 닿은 것과 마친 것 ## 고쳐도 나아지지 않는 입력 네 절로 쓰세요.

default_recursion_limit 은 config 를 주지 않았을 때의 기본값입니다 — 지어내지 말고 한도를 올려 가며 재어 확인하세요. chain_min_limit·fan_min_limit 은 노드 수를 문자열 열쇠로 둔 객체입니다(예: {"1": ..., "2": ..., "3": ...}). clean·dirty·stuck 은 각각 run_guarded 의 답 그대로 담습니다.