prompt는 명령 실행기가 아니다
prompt는 모델에 과업·관측/허용 기능과 출력 조건을 주는 입력이다. 좋은 형식의 제안을 얻으려면 지시문과 현재 관측의 출처/유효 조건, 사용할 skill 목록/인자와 모호할 때 보류할 조건을 구분한다. 모델이 본 문서/영상의 텍스트를 새로운 실행 권한으로 취급하지 않고, 실제 기능과 제약은 실행기가 관리하는 계약으로 둔다.
합성 과업은 등록된 inspection 목표로 이동하는 것이다. 모델은 move_named_pose라는 허용 skill과 target_id만 제안할 수 있다. 현재 물리 상태가 유효한지와 등록된 목표/공구·scene 버전이 맞는지는 실행기가 별도 확인한다. '충돌 검사를 하지 말라' 같은 자유 문장을 같이 출력해도 실행 옵션으로 사용하지 않는다. 이는 모델을 더 설득력 있게 만드는 요령보다 제안과 실행의 책임을 분리하는 설계다.
입력 예의 핵심은 '허용 skill/target 목록을 사용해 제안하라. 불명확하면 실행 가능한 것처럼 만들지 말고 보류하라. 아래 schema 형식만 반환하라'다. 과업/관측을 이 계약과 분리해 넣고 실제 응용의 보류/오류 schema도 정의한다. 이 단위는 성공 제안의 작은 schema만 다루며 자유 텍스트 응답을 실패 없이 모두 실행하는 시스템을 만들지 않는다.
JSON이 읽히는 것과 올바른 제안인 것은 다르다
모델 제안은 다음처럼 값/필드를 제한한다. 이는 ROS의 표준 action 메시지가 아니라 교육용 응용 제안이다.
그림 M22.02-1. 각 칸은 서로 다른 역할/근거다. 아래 방향은 자료/처리의 연결이며 실제 성공을 자동으로 보장하지 않는다. 직접 제작한 개념도이며 본문의 조건과 함께 읽는다.
{"skill":"move_named_pose","target_id":"inspection"}
JSON 문법이 맞아도 skill이 문자열이 아니거나 target_id가 등록되지 않은 값이면 계약 위반이다. 스키마는 object/자료형·필수 필드와 허용 enum/추가 필드 금지 등을 명시한다. JSON Schema 공식 object 설명의 properties만 써서는 필수/추가 필드 금지가 자동 설정되지 않으므로 required/additionalProperties의 역할도 확인한다. 스키마 통과는 단위/현재 장면·기하/운영 상태까지 검증한 결과가 아니다.
아래는 해당 두 필드의 제한만 검사하는 완전한 표준 Python 예다. 범용 JSON Schema 구현이 아니며 ROS client도 아니다. 비표준 상수/중복 키를 거부하고 텍스트 길이를 제한한다.
import json
def reject_constant(value):
raise ValueError(f"nonstandard JSON constant: {value}")
def unique_object(pairs):
result = {}
for key, value in pairs:
if key in result:
raise ValueError("duplicate key")
result[key] = value
return result
def parse_proposal(text):
if len(text) > 4096:
raise ValueError("proposal too long")
obj = json.loads(text, parse_constant=reject_constant,
object_pairs_hook=unique_object)
if type(obj) is not dict or set(obj) != {"skill", "target_id"}:
raise ValueError("wrong fields")
if type(obj["skill"]) is not str or type(obj["target_id"]) is not str:
raise ValueError("wrong types")
if obj["skill"] != "move_named_pose" or obj["target_id"] != "inspection":
raise ValueError("unsupported proposal")
return obj
print(parse_proposal('{"skill":"move_named_pose","target_id":"inspection"}'))
출력은 두 문자열의 Python dict다. 파싱/필드 검사만 수행하며 목표 좌표를 계산하거나 이동하지 않는다. Python3.13 json 문서의 객체/상수 처리와 응용 제한을 구분한다. 실제 서비스는 입력 크기/깊이·오류 처리 등 운영 조건도 별도 검증해야 한다.
실행 봉투는 모델이 스스로 승인하지 않는다
검증한 제안을 adapter에 넘긴다. adapter는 skill의 논리 인자를 해당 로봇의 계획/실행 인터페이스에 연결하는 코드다. inspection이라는 이름은 실행기가 가진 목표 registry에서 실제 pose/단위·프레임·TCP/버전으로 해석한다. 모델이 임의 좌표를 써도 같은 목표라고 간주하지 않는다. 관절 범위·IK/경로·운영 모드/승인 조건을 확인하고 결과를 inspect할 수 있는 dry-run과 실제 실행을 구분한다.
요청 ID/기준 시각·TTL과 scene revision은 신뢰된 실행 측이 붙이는 봉투(envelope)로 둔다. 모델 제안에서 읽은 '최신' 문자열이나 모델이 만든 시각을 권위 있는 사실로 사용하지 않는다. 합성 봉투는 request_id=r7, 검증한 scene=S7, issued_at=1000 ms/허용 입장 시간 TTL=200 ms라고 하자. 이 예의 시각은 모두 같은 simulation clock이고 발급 주체/시계 ID가 알려져 있다.
현재 1100 ms면 나이 100 ms로 이 입장 기준에 맞지만 1250이면 250 ms로 50 ms 초과다. scene이 S8로 바뀌었거나 목표 registry/TCP 버전이 바뀌었다면 TTL 안이라도 과거 검증을 그대로 적용하지 않는다. 재계획/재검증이 필요하다. 이름/자료형만 맞는 제안에 현재 상태가 맞는지 묻는 단계다.
봉투의 나이와 관측 자료의 나이는 다르다. 새 봉투를 발급했다고 오래된 관측이 최신이 되지는 않으므로 관측 취득 시각/유효성도 별도로 확인한다. 이 TTL은 이번 예에서 새 실행을 받아들이는 유효 시간이다. 유효하게 수락한 action이 1200 ms 뒤까지 계속되면 자동 정지한다는 뜻이 아니다. 실행 중 deadline/관측 최신성·취소/정지 조건은 별도 정책이다. 시계를 넘나드는 원격 monotonic 값을 바로 비교하지 않고 공통 기준/변환을 확인한다.
Action 상태는 단계별로 관측한다
ROS2 공식 Action 설계는 goal의 수락/실행·feedback과 result, 취소 요청을 구분한다. 응용 adapter는 허용 skill을 실제 제공되는 action type/server와 입력 단위로 연결하고 목표 ID를 추적한다. 특정 표준 action이 모든 named-pose 의미/검증을 자동 제공하는 것으로 쓰지 않는다. 로봇별 계획기/제어기와 결과 의미를 확인한다.
수락은 server가 목표를 받아들였다는 뜻이고, feedback은 진행 상태다. 최종 SUCCEEDED/ABORTED/CANCELED 등의 상태와 실제 result를 확인해야 한다. 수락 직후 LLM이 '완료'라고 요약해도 완료 근거가 되지 않는다. 실제 관절/목표 도달과 물체 유지/배치 등 과업 후조건도 필요하다. 어떤 action의 성공이 어느 후조건까지 보장하는지 계약에 적는다.
취소 요청에 대한 응답은 요청을 처리했는지의 정보이며 실제 작업/물리 정지가 이미 완료됐다는 뜻과 구분한다. terminal 결과/장치 상태를 확인한다. 특히 통신 timeout은 client가 기다리는 동안 결과를 받지 못했다는 뜻으로, server에서 아무 일도 하지 않았다는 증거가 아니다. 요청을 새 ID로 무조건 다시 보내면 같은 움직임이 중복될 수 있다.
요청의 중복과 미상을 보존한다
응용 request_id와 ROS goal UUID의 대응, 현재 상태·최종 결과를 실행 측에 기록한다. r7이 이미 실행 중이면 같은 요청을 새 동작으로 처리하지 않고 기존 상태를 조회/연결하는 정책을 둔다. 저장된 상태가 사라진 재시작/네트워크 단절에서는 '실행 안 됨'으로 초기화하지 말고 미상으로 두어 server/관측과 조정한다. ID를 붙인 것만으로 모든 장애 상황의 exactly-once 실행이 보장되지는 않는다.
흐름을 제안→형식 검사→의미/현재 상태 검증→목표 계획/실행→피드백/최종 결과·후조건 확인으로 나누고 실패 위치를 기록한다. model 출력/parse 결과와 검증/전송·실제 결과를 다른 열에 둔다. 기존 3.5 안전한 실행 루프와 기존 5.9 추론 파이프라인을 연결해 제안의 숫자가 실제 목표가 되기까지의 검사를 살펴보자. 이번 활동은 도구나 ROS 메시지를 보내지 않는다.